{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# <center/>优化数据准备的性能"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 概述\n",
    "\n",
    "数据是整个深度学习中最重要的一环，因为数据的好坏决定了最终结果的上限，模型的好坏只是去无限逼近这个上限，所以高质量的数据输入，会在整个深度神经网络中起到积极作用，数据在整个数据处理和数据增强的过程像经过pipeline管道的水一样，源源不断地流向训练系统，如图所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![title](https://gitee.com/mindspore/docs/raw/master/tutorials/notebook/optimize_the_performance_of_data_preparation/images/pipeline.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "MindSpore为用户提供了数据处理以及数据增强的功能，在数据的整个pipeline过程中，其中的每一步骤，如果都能够进行合理的运用，那么数据的性能会得到很大的优化和提升。本次体验将基于CIFAR-10数据集来为大家展示如何在数据加载、数据处理和数据增强的过程中进行性能的优化。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 整体流程\n",
    "- 准备环节。\n",
    "- 数据加载性能优化。\n",
    "- shuffle性能优化。\n",
    "- 数据增强性能优化。\n",
    "- 性能优化方案总结。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 准备环节"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 导入模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`dataset`模块提供API用来加载和处理数据集。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import mindspore.dataset as ds"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`numpy`模块用于生成ndarray数组。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 下载所需数据集"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行以下命令来获取数据集："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2020-12-03 17:30:26--  https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/datasets/cifar10.zip\n",
      "Resolving proxy-notebook.modelarts-dev-proxy.com (proxy-notebook.modelarts-dev-proxy.com)... 192.168.0.172\n",
      "Connecting to proxy-notebook.modelarts-dev-proxy.com (proxy-notebook.modelarts-dev-proxy.com)|192.168.0.172|:8083... connected.\n",
      "Proxy request sent, awaiting response... 200 OK\n",
      "Length: 166235630 (159M) [application/zip]\n",
      "Saving to: ‘cifar10.zip’\n",
      "\n",
      "cifar10.zip         100%[===================>] 158.53M  58.1MB/s    in 2.7s    \n",
      "\n",
      "2020-12-03 17:30:29 (58.1 MB/s) - ‘cifar10.zip’ saved [166235630/166235630]\n",
      "\n",
      "Archive:  cifar10.zip\n",
      "   creating: ./datasets/cifar10/\n",
      "   creating: ./datasets/cifar10/test/\n",
      "  inflating: ./datasets/cifar10/test/test_batch.bin  \n",
      "   creating: ./datasets/cifar10/train/\n",
      "  inflating: ./datasets/cifar10/train/batches.meta.txt  \n",
      "  inflating: ./datasets/cifar10/train/data_batch_1.bin  \n",
      "  inflating: ./datasets/cifar10/train/data_batch_2.bin  \n",
      "  inflating: ./datasets/cifar10/train/data_batch_3.bin  \n",
      "  inflating: ./datasets/cifar10/train/data_batch_4.bin  \n",
      "  inflating: ./datasets/cifar10/train/data_batch_5.bin  \n",
      "./datasets/cifar10\n",
      "├── test\n",
      "│   └── test_batch.bin\n",
      "└── train\n",
      "    ├── batches.meta.txt\n",
      "    ├── data_batch_1.bin\n",
      "    ├── data_batch_2.bin\n",
      "    ├── data_batch_3.bin\n",
      "    ├── data_batch_4.bin\n",
      "    └── data_batch_5.bin\n",
      "\n",
      "2 directories, 7 files\n"
     ]
    }
   ],
   "source": [
    "! wget -N https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/datasets/cifar10.zip\n",
    "! unzip -o cifar10.zip -d ./datasets\n",
    "! tree ./datasets/cifar10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2020-12-03 17:30:32--  https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/datasets/cifar10-py.zip\n",
      "Resolving proxy-notebook.modelarts-dev-proxy.com (proxy-notebook.modelarts-dev-proxy.com)... 192.168.0.172\n",
      "Connecting to proxy-notebook.modelarts-dev-proxy.com (proxy-notebook.modelarts-dev-proxy.com)|192.168.0.172|:8083... connected.\n",
      "Proxy request sent, awaiting response... 200 OK\n",
      "Length: 170647614 (163M) [application/zip]\n",
      "Saving to: ‘cifar10-py.zip’\n",
      "\n",
      "cifar10-py.zip      100%[===================>] 162.74M  62.0MB/s    in 2.6s    \n",
      "\n",
      "2020-12-03 17:30:35 (62.0 MB/s) - ‘cifar10-py.zip’ saved [170647614/170647614]\n",
      "\n",
      "Archive:  cifar10-py.zip\n",
      "   creating: ./datasets/cifar-10-batches-py/\n",
      "  inflating: ./datasets/cifar-10-batches-py/batches.meta  \n",
      "  inflating: ./datasets/cifar-10-batches-py/data_batch_1  \n",
      "  inflating: ./datasets/cifar-10-batches-py/data_batch_2  \n",
      "  inflating: ./datasets/cifar-10-batches-py/data_batch_3  \n",
      "  inflating: ./datasets/cifar-10-batches-py/data_batch_4  \n",
      "  inflating: ./datasets/cifar-10-batches-py/data_batch_5  \n",
      "  inflating: ./datasets/cifar-10-batches-py/readme.html  \n",
      "  inflating: ./datasets/cifar-10-batches-py/test_batch  \n",
      "./datasets/cifar-10-batches-py\n",
      "├── batches.meta\n",
      "├── data_batch_1\n",
      "├── data_batch_2\n",
      "├── data_batch_3\n",
      "├── data_batch_4\n",
      "├── data_batch_5\n",
      "├── readme.html\n",
      "└── test_batch\n",
      "\n",
      "0 directories, 8 files\n"
     ]
    }
   ],
   "source": [
    "! wget -N https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/datasets/cifar10-py.zip\n",
    "! unzip -o cifar10-py.zip -d ./datasets\n",
    "! tree ./datasets/cifar-10-batches-py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据加载性能优化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "MindSpore为用户提供了多种数据加载方式，其中包括常用数据集加载、用户自定义数据集加载、MindSpore数据格式加载，详情内容请参考[加载数据集](https://www.mindspore.cn/doc/programming_guide/zh-CN/master/dataset_loading.html)。对于数据集加载，底层实现方式的不同，会导致数据集加载的性能存在差异，如下所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "|      | 常用数据集 | 用户自定义 | MindRecord |\n",
    "| :----: | :----: | :----: | :----: |\n",
    "| 底层实现 | C++ | Python | C++ |\n",
    "| 性能 | 高 | 中 | 高|"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 性能优化方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![title](https://gitee.com/mindspore/docs/raw/master/tutorials/notebook/optimize_the_performance_of_data_preparation/images/data_loading_performance_scheme.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数据加载性能优化建议如下：\n",
    "- 已经支持的数据集格式优选内置加载算子，具体内容请参考[内置加载算子](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.html)，如果性能仍无法满足需求，则可采取多线程并发方案，请参考本文[多线程优化方案](#多线程优化方案)。\n",
    "- 不支持的数据集格式，优选转换为MindSpore数据格式后再使用`MindDataset`类进行加载，具体内容请参考[将数据集转换为MindSpore数据格式](https://www.mindspore.cn/tutorial/training/zh-CN/master/advanced_use/convert_dataset.html)，如果性能仍无法满足需求，则可采取多线程并发方案，请参考本文[多线程优化方案](#多线程优化方案)。\n",
    "- 不支持的数据集格式，算法快速验证场景，优选用户自定义`GeneratorDataset`类实现，如果性能仍无法满足需求，则可采取多进程并发方案，请参考本文[多进程优化方案](#多进程优化方案)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 代码示例\n",
    "\n",
    "基于以上的数据加载性能优化建议，本次体验分别使用内置加载算子`Cifar10Dataset`类、数据转换后使用`MindDataset`类、使用`GeneratorDataset`类进行数据加载，代码演示如下："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 使用内置算子`Cifar10Dataset`类加载CIFAR-10数据集，这里使用的是CIFAR-10二进制格式的数据集，加载数据时采取多线程优化方案，开启了4个线程并发完成任务，最后对数据创建了字典迭代器，并通过迭代器读取了一条数据记录。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'image': Tensor(shape=[32, 32, 3], dtype=UInt8, value=\n",
      "[[[  7,   7,   6],\n",
      "  [  4,   4,   3],\n",
      "  [  4,   4,   4],\n",
      "  ...\n",
      "  [ 76,  69,  66],\n",
      "  [ 78,  69,  66],\n",
      "  [ 70,  65,  62]],\n",
      " [[  4,   4,   4],\n",
      "  [  4,   4,   4],\n",
      "  [  4,   4,   4],\n",
      "  ...\n",
      "  [ 84,  79,  69],\n",
      "  [ 76,  69,  59],\n",
      "  [ 59,  55,  48]],\n",
      " [[  4,   4,   4],\n",
      "  [  4,   4,   4],\n",
      "  [  4,   4,   4],\n",
      "  ...\n",
      "  [ 67,  60,  52],\n",
      "  [ 55,  46,  39],\n",
      "  [ 65,  62,  57]],\n",
      " ...\n",
      " [[ 94,  84,  81],\n",
      "  [112, 105, 102],\n",
      "  [111, 102,  95],\n",
      "  ...\n",
      "  [220, 220, 222],\n",
      "  [225, 225, 226],\n",
      "  [215, 215, 217]],\n",
      " [[ 93,  86,  81],\n",
      "  [ 93,  83,  82],\n",
      "  [107,  98,  95],\n",
      "  ...\n",
      "  [228, 228, 230],\n",
      "  [239, 239, 240],\n",
      "  [215, 215, 217]],\n",
      " [[139, 137, 137],\n",
      "  [106, 101,  97],\n",
      "  [ 89,  81,  78],\n",
      "  ...\n",
      "  [216, 216, 219],\n",
      "  [216, 215, 218],\n",
      "  [197, 196, 199]]]), 'label': Tensor(shape=[], dtype=UInt32, value= 1)}\n"
     ]
    }
   ],
   "source": [
    "cifar10_path = \"./datasets/cifar10/train\"\n",
    "\n",
    "# create Cifar10Dataset for reading data\n",
    "cifar10_dataset = ds.Cifar10Dataset(cifar10_path,num_parallel_workers=4)\n",
    "# create a dictionary iterator and read a data record through the iterator\n",
    "print(next(cifar10_dataset.create_dict_iterator()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2. 使用`Cifar10ToMR`这个类将CIFAR-10数据集转换为MindSpore数据格式，这里使用的是CIFAR-10 python文件格式的数据集，然后使用`MindDataset`类加载MindSpore数据格式数据集，加载数据采取多线程优化方案，开启了4个线程并发完成任务，最后对数据创建了字典迭代器，并通过迭代器读取了一条数据记录。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'data': Tensor(shape=[1280], dtype=UInt8, value= [255, 216, 255, 224,   0,  16,  74,  70,  73,  70,   0,   1,   1,   0,   0,   1,   0,   1,   0,   0, 255, 219,   0,  67, \n",
      "   0,   2,   1,   1,   1,   1,   1,   2,   1,   1,   1,   2,   2,   2,   2,   2,   4,   3,   2,   2,   2,   2,   5,   4, \n",
      "   4,   3,   4,   6,   5,   6,   6,   6,   5,   6,   6,   6,   7,   9,   8,   6,   7,   9,   7,   6,   6,   8,  11,   8, \n",
      "   9,  10,  10,  10,  10,  10,   6,   8,  11,  12,  11,  10,  12,   9,  10,  10,  10, 255, 219,   0,  67,   1,   2,   2, \n",
      "   2,   2,   2,   2,   5,   3,   3,   5,  10,   7,   6,   7,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10, \n",
      "  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10, \n",
      "  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10,  10, 255, 192,   0,  17,   8,   0,  32,   0,  32,   3, \n",
      "   1,  34,   0,   2,  17,   1,   3,  17,   1, 255, 196,   0,  31,   0,   0,   1,   5,   1,   1,   1,   1,   1,   1,   0, \n",
      "   0,   0,   0,   0,   0,   0,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11, 255, 196,   0, 181,  16,   0, \n",
      "   2,   1,   3,   3,   2,   4,   3,   5,   5,   4,   4,   0,   0,   1, 125,   1,   2,   3,   0,   4,  17,   5,  18,  33, \n",
      "  49,  65,   6,  19,  81,  97,   7,  34, 113,  20,  50, 129, 145, 161,   8,  35,  66, 177, 193,  21,  82, 209, 240,  36, \n",
      "  51,  98, 114, 130,   9,  10,  22,  23,  24,  25,  26,  37,  38,  39,  40,  41,  42,  52,  53,  54,  55,  56,  57,  58, \n",
      "  67,  68,  69,  70,  71,  72,  73,  74,  83,  84,  85,  86,  87,  88,  89,  90,  99, 100, 101, 102, 103, 104, 105, 106, \n",
      " 115, 116, 117, 118, 119, 120, 121, 122, 131, 132, 133, 134, 135, 136, 137, 138, 146, 147, 148, 149, 150, 151, 152, 153, \n",
      " 154, 162, 163, 164, 165, 166, 167, 168, 169, 170, 178, 179, 180, 181, 182, 183, 184, 185, 186, 194, 195, 196, 197, 198, \n",
      " 199, 200, 201, 202, 210, 211, 212, 213, 214, 215, 216, 217, 218, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 241, \n",
      " 242, 243, 244, 245, 246, 247, 248, 249, 250, 255, 196,   0,  31,   1,   0,   3,   1,   1,   1,   1,   1,   1,   1,   1, \n",
      "   1,   0,   0,   0,   0,   0,   0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11, 255, 196,   0, 181,  17,   0, \n",
      "   2,   1,   2,   4,   4,   3,   4,   7,   5,   4,   4,   0,   1,   2, 119,   0,   1,   2,   3,  17,   4,   5,  33,  49, \n",
      "   6,  18,  65,  81,   7,  97, 113,  19,  34,  50, 129,   8,  20,  66, 145, 161, 177, 193,   9,  35,  51,  82, 240,  21, \n",
      "  98, 114, 209,  10,  22,  36,  52, 225,  37, 241,  23,  24,  25,  26,  38,  39,  40,  41,  42,  53,  54,  55,  56,  57, \n",
      "  58,  67,  68,  69,  70,  71,  72,  73,  74,  83,  84,  85,  86,  87,  88,  89,  90,  99, 100, 101, 102, 103, 104, 105, \n",
      " 106, 115, 116, 117, 118, 119, 120, 121, 122, 130, 131, 132, 133, 134, 135, 136, 137, 138, 146, 147, 148, 149, 150, 151, \n",
      " 152, 153, 154, 162, 163, 164, 165, 166, 167, 168, 169, 170, 178, 179, 180, 181, 182, 183, 184, 185, 186, 194, 195, 196, \n",
      " 197, 198, 199, 200, 201, 202, 210, 211, 212, 213, 214, 215, 216, 217, 218, 226, 227, 228, 229, 230, 231, 232, 233, 234, \n",
      " 242, 243, 244, 245, 246, 247, 248, 249, 250, 255, 218,   0,  12,   3,   1,   0,   2,  17,   3,  17,   0,  63,   0, 241, \n",
      " 127, 132, 255,   0, 240,  78, 127, 142,  31,  30, 210,  77,  83, 225, 191, 194, 171, 133, 179, 151,  50, 180, 218, 140, \n",
      " 177, 192, 177, 177, 254, 243,  74,  84, 117, 224,  48,  28, 241,  95,  59, 120,  55, 192, 126,  13, 210, 255,   0, 107, \n",
      " 175,  18, 124,  17, 253, 166, 126,  35, 216, 248,  50, 247, 194, 183, 199,  77, 158, 218, 233,  60, 199, 184,   9, 212, \n",
      " 199,  50,  55, 150,  88, 231,  60, 246, 233, 154, 246, 191, 248,  40, 143, 237, 249, 241,  98,  95,  29, 234,  31, 179, \n",
      "  30, 139, 241,  69, 224, 211, 252,  63, 114, 250, 125, 253, 230, 143, 121,  50, 139, 169,  99, 251, 192, 200, 205, 187, \n",
      " 106, 156, 140,  41,  10,  72, 175, 137, 117, 255,   0,   6, 104,  62,  35, 255,   0, 137, 165, 213, 165, 189, 236, 132, \n",
      "  18, 110,  38, 145, 149, 223,  39, 169, 108, 228, 156, 250, 215, 159, 130, 202, 163,  69, 115,  61, 204, 169, 209, 167, \n",
      "  67, 212, 253,  19, 135,  76, 255,   0, 130, 113, 252,  21, 214, 109,  60,  87, 164, 252, 111, 190,  48, 197, 110,  35, \n",
      " 142, 219,  78, 212,  46,  26, 238, 230, 241, 153,  66,  18, 204, 194,  37, 143,  25,   7,  43, 142, 107, 233, 127, 217, \n",
      " 183,  69, 248, 225, 115, 227, 180, 214, 126,  38, 126, 206, 154, 156, 158,  19, 190, 148, 253, 130, 242, 211,  91, 137, \n",
      "  26,  56, 155, 253,  92, 164, 130, 200,  84, 142, 160,  31, 165, 126,  40, 232, 223,  11, 188,  47, 166, 235, 150, 151, \n",
      " 126,  38, 186, 185,  77,  58,  41,  22,  75, 155,  40, 174,  79, 239, 144,  17, 242, 134,  63, 119,  53, 251, 145, 240, \n",
      "  43, 246, 192, 253, 156, 252,  75, 251,  49, 120, 117, 172, 124,  33, 118, 108, 109, 109,  34, 182, 176, 213, 227, 188, \n",
      " 146,  51,  15, 150, 129,  68,  77,  30,  24,  51,  41,  24,   7,  28, 250, 213, 226, 112, 156, 182, 147, 147, 185, 232, \n",
      "  81, 197,  70, 146, 146, 246, 113, 146, 106, 218, 254, 106, 205,  89, 175, 248, 115, 241, 135, 246, 174, 240, 110, 183, \n",
      " 240, 235, 227,  39, 137,  52,  63,  22, 106,  54, 247,  87,  48, 234, 211,  11, 136,  50,   9, 243,  55, 146, 100, 249, \n",
      "  58,  14, 227, 158, 245, 229, 209, 248, 215,  84, 211, 173,  82, 255,   0,  68, 176,  23,  49, 171,  21, 222, 239, 187, \n",
      " 107,  14,   1,  32, 244, 246, 175, 160,  63, 110,  11, 159,   4, 252,  99, 253, 166, 188,  97, 227, 239,   5,  65, 119, \n",
      "  30, 151, 169, 106,  45, 229,  77,  42, 130, 100,  32,   0, 236, 187,  20,  46, 210, 192, 145, 192, 226, 184, 111, 135, \n",
      "  95,  10, 111,  47,  45, 158, 199, 193,  62,   7, 191, 191, 127,  49, 183, 139, 107,  86, 118, 115, 143, 188, 210,  17, \n",
      " 133,  31,  79, 202, 187, 149, 100, 160, 155, 103,  52, 149, 228, 112, 169, 101, 241,  55, 226,  94, 181, 107, 165, 248, \n",
      " 127,  76, 187, 190, 187, 188,  79,  45, 237, 225, 132, 176,  80, 216,   5, 176,   7,   0,  12, 242, 122, 117, 175, 208, \n",
      " 207, 217, 255,   0, 194, 145, 124,  31, 248,  39,  97, 224,  79,  13,  71, 174, 255,   0, 111,  89, 216, 134,  55,  22, \n",
      "  26, 150, 200, 214, 102,  57, 103,  10, 207, 142,  51, 140, 227,  60,  87, 157, 126, 198, 255,   0, 176, 247, 199,  63, \n",
      "  17, 235, 119, 218,  84, 150, 235, 162, 253, 173,   5, 196, 218, 125, 149, 222, 103, 120,  23,  25, 249, 157, 209,  92, \n",
      " 231,  31,  40,  36, 143,  74, 251,  95, 225, 207, 236, 217, 240,  67, 225,  45, 138, 203, 172,  75, 113, 107, 173,  70, \n",
      "  81, 165,  58, 253, 188, 247,  55,   4, 177, 224,  70,   1,  40,  65, 250, 100,  87,  60, 177, 148, 249,  95,  50, 252, \n",
      " 138, 157,  37, 165, 157, 207, 255, 217]), 'id': Tensor(shape=[], dtype=Int64, value= 21750), 'label': Tensor(shape=[], dtype=Int64, value= 2)}\n"
     ]
    }
   ],
   "source": [
    "from mindspore.mindrecord import Cifar10ToMR\n",
    "import os\n",
    "\n",
    "trans_path = \"./transform/\"\n",
    "if not os.path.exists(trans_path):\n",
    "    os.mkdir(trans_path)\n",
    "os.system(\"rm -f {}cifar10*\".format(trans_path))\n",
    "cifar10_path = './datasets/cifar-10-batches-py'\n",
    "cifar10_mindrecord_path = './transform/cifar10.record'\n",
    "\n",
    "cifar10_transformer = Cifar10ToMR(cifar10_path,cifar10_mindrecord_path)\n",
    "# executes transformation from Cifar10 to MindRecord\n",
    "cifar10_transformer.transform(['label'])\n",
    "\n",
    "# create MindDataset for reading data\n",
    "cifar10_mind_dataset = ds.MindDataset(dataset_file=cifar10_mindrecord_path,num_parallel_workers=4)\n",
    "# create a dictionary iterator and read a data record through the iterator\n",
    "print(next(cifar10_mind_dataset.create_dict_iterator()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "3. 使用`GeneratorDataset`类加载自定义数据集，并且采取多进程优化方案，开启了4个进程并发完成任务，最后对数据创建了字典迭代器，并通过迭代器读取了一条数据记录。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'data': Tensor(shape=[1], dtype=Int64, value= [0])}\n"
     ]
    }
   ],
   "source": [
    "def generator_func(num):\n",
    "    for i in range(num):\n",
    "        yield (np.array([i]),)\n",
    "\n",
    "# create GeneratorDataset for reading data\n",
    "dataset = ds.GeneratorDataset(source=generator_func(5),column_names=[\"data\"],num_parallel_workers=4)\n",
    "# create a dictionary iterator and read a data record through the iterator\n",
    "print(next(dataset.create_dict_iterator()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## shuffle性能优化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "shuffle操作主要是对有序的数据集或者进行过repeat的数据集进行混洗，MindSpore专门为用户提供了`shuffle`函数，其中设定的`buffer_size`参数越大，混洗程度越大，但时间、计算资源消耗也会大。该接口支持用户在整个pipeline的任何时候都可以对数据进行混洗，具体内容请参考[shuffle处理](https://www.mindspore.cn/doc/programming_guide/zh-CN/master/pipeline.html#shuffle)。但是因为底层的实现方式不同，该方式的性能不如直接在[内置加载算子](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.html)中设置`shuffle`参数直接对数据进行混洗。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 性能优化方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![title](https://gitee.com/mindspore/docs/raw/master/tutorials/notebook/optimize_the_performance_of_data_preparation/images/shuffle_performance_scheme.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "shuffle性能优化建议如下：\n",
    "- 直接使用内置加载算子的`shuffle`参数进行数据的混洗。\n",
    "- 如果使用的是`shuffle`函数，当性能仍无法满足需求，可通过调大`buffer_size`参数的值来优化提升性能。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 代码示例\n",
    "\n",
    "基于以上的shuffle性能优化建议，本次体验分别使用内置加载算子`Cifar10Dataset`类的`shuffle`参数和`Shuffle`函数进行数据的混洗，代码演示如下："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 使用内置算子`Cifar10Dataset`类加载CIFAR-10数据集，这里使用的是CIFAR-10二进制格式的数据集，并且设置`shuffle`参数为True来进行数据混洗，最后对数据创建了字典迭代器，并通过迭代器读取了一条数据记录。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'image': Tensor(shape=[32, 32, 3], dtype=UInt8, value=\n",
      "[[[ 17,  18,  27],\n",
      "  [ 21,  25,  27],\n",
      "  [ 36,  39,  29],\n",
      "  ...\n",
      "  [ 32,  34,  30],\n",
      "  [ 34,  38,  25],\n",
      "  [135, 142, 140]],\n",
      " [[  4,   5,   9],\n",
      "  [ 19,  21,  21],\n",
      "  [ 63,  60,  49],\n",
      "  ...\n",
      "  [ 10,  11,   9],\n",
      "  [ 22,  25,  12],\n",
      "  [ 80,  89,  76]],\n",
      " [[  4,   3,   7],\n",
      "  [  6,  12,   5],\n",
      "  [ 53,  53,  45],\n",
      "  ...\n",
      "  [  2,   6,   5],\n",
      "  [  5,  11,   4],\n",
      "  [ 18,  28,  17]],\n",
      " ...\n",
      " [[ 23,  37,  11],\n",
      "  [ 35,  47,  20],\n",
      "  [ 33,  45,  18],\n",
      "  ...\n",
      "  [ 54,  61,  20],\n",
      "  [ 61,  66,  26],\n",
      "  [ 61,  64,  26]],\n",
      " [[ 31,  43,  10],\n",
      "  [ 35,  47,  16],\n",
      "  [ 42,  54,  17],\n",
      "  ...\n",
      "  [ 50,  57,  23],\n",
      "  [ 49,  55,  21],\n",
      "  [ 54,  57,  23]],\n",
      " [[ 40,  43,  13],\n",
      "  [ 41,  43,  19],\n",
      "  [ 46,  47,  15],\n",
      "  ...\n",
      "  [ 63,  65,  25],\n",
      "  [ 60,  63,  22],\n",
      "  [ 56,  61,  18]]]), 'label': Tensor(shape=[], dtype=UInt32, value= 7)}\n"
     ]
    }
   ],
   "source": [
    "cifar10_path = \"./datasets/cifar10/train\"\n",
    "\n",
    "# create Cifar10Dataset for reading data\n",
    "cifar10_dataset = ds.Cifar10Dataset(cifar10_path,shuffle=True)\n",
    "# create a dictionary iterator and read a data record through the iterator\n",
    "print(next(cifar10_dataset.create_dict_iterator()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2. 使用`shuffle`函数进行数据混洗，参数`buffer_size`设置为3，数据采用`GeneratorDataset`类自定义生成。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "before shuffle:\n",
      "[0 1 2 3 4]\n",
      "[1 2 3 4 5]\n",
      "[2 3 4 5 6]\n",
      "[3 4 5 6 7]\n",
      "[4 5 6 7 8]\n",
      "after shuffle:\n",
      "[2 3 4 5 6]\n",
      "[0 1 2 3 4]\n",
      "[1 2 3 4 5]\n",
      "[3 4 5 6 7]\n",
      "[4 5 6 7 8]\n"
     ]
    }
   ],
   "source": [
    "def generator_func():\n",
    "    for i in range(5):\n",
    "        yield (np.array([i,i+1,i+2,i+3,i+4]),)\n",
    "\n",
    "ds1 = ds.GeneratorDataset(source=generator_func,column_names=[\"data\"])\n",
    "print(\"before shuffle:\")\n",
    "for data in ds1.create_dict_iterator():\n",
    "    print(data[\"data\"])\n",
    "\n",
    "ds2 = ds1.shuffle(buffer_size=3)\n",
    "print(\"after shuffle:\")\n",
    "for data in ds2.create_dict_iterator():\n",
    "    print(data[\"data\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据增强性能优化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在图片分类的训练中，尤其是当数据集比较小的时候，用户可以使用数据增强的方式来预处理图片，从而丰富数据集。MindSpore为用户提供了多种数据增强的方式，其中包括：\n",
    "- 使用内置C算子（`c_transforms`模块）进行数据增强。\n",
    "- 使用内置Python算子（`py_transforms`模块）进行数据增强。\n",
    "- 用户可根据自己的需求，自定义Python函数进行数据增强。\n",
    "\n",
    "具体的内容请参考[数据增强](https://www.mindspore.cn/doc/programming_guide/zh-CN/master/augmentation.html)。因为底层的实现方式不同，所以性能还是有一定的差异，如下所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "|   模块   | 底层接口 | 说明 |\n",
    "| :----: | :----: | :----: |\n",
    "| c_transforms | C++（基于OpenCV）| 性能高 |\n",
    "| py_transforms | Python（基于PIL） | 该模块提供了多种图像增强功能，并提供了PIL Image和Numpy数组之间的传输方法 |\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 性能优化方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![title](https://gitee.com/mindspore/docs/raw/master/tutorials/notebook/optimize_the_performance_of_data_preparation/images/data_enhancement_performance_scheme.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数据增强性能优化建议如下：\n",
    "- 优先使用`c_transforms`模块进行数据增强，因为性能最高，如果性能仍无法满足需求，可采取[多线程优化方案](#多线程优化方案)、[Compose优化方案](#Compose优化方案)或者[算子融合优化方案](#算子融合优化方案)。\n",
    "- 如果使用了`py_transforms`模块进行数据增强，当性能仍无法满足需求，可采取[多线程优化方案](#多线程优化方案)、[多进程优化方案](#多进程优化方案)、[Compose优化方案](#Compose优化方案)或者[算子融合优化方案](#算子融合优化方案)。\n",
    "- `c_transforms`模块是在C++内维护buffer管理，`py_transforms`模块是在Python内维护buffer管理。因为Python和C++切换的性能成本，建议不要混用算子。\n",
    "- 如果用户使用了自定义Python函数进行数据增强，当性能仍无法满足需求，可采取[多线程优化方案](#多线程优化方案)或者[多进程优化方案](#多进程优化方案)，如果还是无法提升性能，就需要对自定义的Python代码进行优化。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 代码示例\n",
    "\n",
    "基于以上的数据增强性能优化建议，本次体验分别使用`c_transforms`模块和自定义Python函数进行了数据增强，演示代码如下所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 使用`c_transforms`模块进行数据增强，数据增强时采用多线程优化方案，开启了4个线程并发完成任务，并且采用了算子融合优化方案，使用`RandomResizedCrop`融合类替代`RandomResize`类和`RandomCrop`类。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQEAAAD8CAYAAAB3lxGOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAACnU0lEQVR4nO39bcx223YWhl1jrud8bH/EJwbHPcKoNsIiQpH4CApBRJWLRQUuwv1BiN0oNaklEgkiUCPFdio1VdUf5k+Iq0Y0iCQ1FY2hTkiQRaHUgKJIjUsMiCh2nByoqY+FcaDGITH22c+aoz/G1zXmXPfz3s/e7z772ec8833vZ60173WvNb/GNa4x5peoKl7Da3gNX7xhfNgJeA2v4TV8uOEVBF7Da/giD68g8Bpewxd5eAWB1/AavsjDKwi8htfwRR5eQeA1vIYv8vCBgICI/BYR+TER+YyIfOcH8Y7X8Bpew9sJ8rbHCYjIAeC/AvCbAXwWwF8C8K2q+iNv9UWv4TW8hrcSPggm8E8A+Iyq/g1V/RyA7wPwzR/Ae17Da3gNbyE8fADP/CUAfoKuPwvg1683icjvBvC7AWAc8o+/82WfuPlAIyvEWJSuFiKj7ct+j745sqex//G/AETq/OKRl5e6n7d8benY3yCXL31mkKsn1xfxnfjL4mjfSR5FBGMMiAyMIRgyIGNgyPB4+37I2F5z4wKqE3NOTJ1QP86LY7JX1dYONE7a9a23XReILDfKRYHJjavt+bqc3miXEGS5jeHlOJZy9LJeH7zKxlPE/v/7kz/xd1T1q9b4DwIE7gqq+ocB/GEA+LJPvaO/6ht+2fo9VAGdflSFzuWoAPh79UJYfpvXeQNaQ8prKkERwRBr7HU+Mi6O9mP75M/pnXHd0j4BzD1OJ7I+xYFGhAUvhNLOo33qFcJs5/5MCTCp59W1mEAf1ugOaowRF5+Pf+zj+OQn38EnP/kO3vmEHT/5iXfwDsd94h184hOfyMZbAuUgmmBqfz/37i/gH/z8z+Hnfv7n8PO/8HN27sd/8PM/h3/wC/b53Od+AXMqVBVT1evZz1X9u7kIRL2TrrIQBQIZsHodVTYjzodU+cU/9edoj0McvU1EHWNpx5j2/cPDg5XfO+/gnXfewTvvfEmef/KTfnznS/CJT3yCZKM+AYz8uQr/4nf8/r95Ff9BmAM/CeCX0vXXeNwHEvSWdlxR+L08+46Y9x3e8Mi3+8bbT3sey6Cbn0rge2Qud/1M2qHCpcrdw/PK9W1QsNvh89LOnggfBAj8JQBfLyJfJyIfB/AtAP7UW30D0zW9iLx9+3t9zfsPtx72hpdcfn1LAN5HeJ5/mG5+KhHvsS3fBPZbz5Qb528tfL4n2X2woLOGt24OqOqjiPxeAH8WwAHg31HV/+LtvoTOBTcaxoVR+L7DvZVz68W3Evv0ky613WLH3vfUtw+Ub37d85/85C+WL7d8a9z00Zkd+/kV+T18ID4BVf3TAP70B/HsO97ux2oIdzeHpe3sAngpkm9+0LMS8eEEvekwfNMP33ZK3vBIveemPXzYgnYZXghWveARg+W4cVdYHaWu2bsrebdfS48zx1R5vbujiN8Zv0P77rpPoL+P4/m60oJ06qVDKp10cS85zsgpGD9kB2Evo56elhrpudvKSnt+7xKaJ/yRYZorOUgj7pZ3PS5lOW8OOVk+8QRZjlc2gmwxS2J3l0I6XdeenNXBbBcXaudayrfyfU8gfNsJuDoKnxoP9KH1DrSQjZqixD3mw73mgEHWrN8AIG966WmFeOWJ/V4VUMmeAkg0THPhakJynIN6BgDBwAAJLFZBWc5kife8YFT7SYUmbgOrnw96NoMBAiRkAxvO+dYL5V8VhlCvQ+ajA+llu1X6ZB7Ue0H8M80zP6d38flnxHsjERrpCEG2lx9j4JADx9g/D+MBD8eBh3FgjgdMTExVDIgdp2IOhcwJHQqZCr0oj8xLY3V031ToEGCKISMEUzTTKaIQjXagiN6B9jzuFdL9fVYEnuuBBDTkcW9CXPiRM1XlKyhm9pI8J7wIEBBYX2gLapWhk45wQbk4AkgBTgDIeMJnIVS8Ohd7d1Z60z7oYEAeLGEUopyljA50pSOA+m8YBBLUWDAlY0jjSXtg5lAZ1ATqvpHqUqxG1p4LYipRWLfaEmtOhdXNDCCYBgbnzI819GFgEI3e3zyofE85vGtyEf4GBA/2XPExAzIMbKAQAgVxkEjtzAo9Soy/EzgdcgUS1Emj0oVsps7CdAUFBoOsz65uaPhFdkkOIcbWiEwJe6ZeZxN/6xJVTAeDm3V3EV4ECACmeVsQE/w5BDIVc4DQGY27si4ESrgaEictrbEDUE0hKVS1ewr5QYBwxQaYY0oJEPeBF9GwtE0694SrAhjGVlr99z9dQ/jN1aC9fAgIlO5fQaRdY39vyAVufhbKOWcygToadRsDUIwCTmIkNtBIjAmMA4cMF/ojjw9HMIEHzOPEnCOBYGA4M5iYEMickIGFDVD9Q72YitKLwhgAFHO6xhfS/EOXtnAl+FyCgep22s3UrjCGjztJ808CtIvTtr/MAJQBgcYLPAMFXgQIiGBjAqoKDMGYCh3AmKbVzDzwcwQToCJmBbnGsWYIzU92nJIANRsURJ+FwaBEsx3lIja0igOEDR5hECBq05K+VGZrZ6HJPO1Qew4xHF1+J+s5lgbaYS3vW+OuBmbN2YHgnMYExJuyjmJbUaYJAiIY4yggCAA4gg3Y52PHA3SeOGUaEPg/EYFMgWDas6dAxnQGqW5FRsOQEhJqAzLVgFmCCTjIilTUwhBHqR4qKRdoKnyNVto0lvit/qxgHFtdFVjZFQEACgCm5tlHlAmM3sxUwxQgoXcl2lolabIs4HYtXPepvaBFpUwIKw5guhY2eBd+Y4wlMu087iLAcJXdgKD8FAsAtAq8qs3its02JH9HmhhcKBdAsJy2uGx/V594f5gDPFpvlikwj5llE2VdyTFvyxgGAFPO9AkYC3gwMDg6GMwxMXDiNPHHFME8BedgDT0hE5jD0hNZmehtAO7L8ApNwYeIsX8XUgODqufhJTQJFFoTpmpbOFy2p2gZY6CPSGzEggq7sRpmAzO1f5w/BwVeCAjItWMQBgBTNPsxBgFCkyl6Vh50fRgQGj+F3r10RRzteyLzJOiZWvquw0OaEBAChgKFEnb3KdB1ZwJsy1ZDKJ8PpVsZALTnhYhhF/6tlVZ+SNhXKy3DZgqo+wPKITiJCZiQCCID6VxzJjBkXDgDOwswk+ABc54mfDIx5cScghPGBCaAE6TMMTHFPMpTi1mZPqCyywbiSkM0HZlxHg69IcY3GhsQ8w2Y04OKNnw3FcFFXu0kAcfu6eWurSZZ+3N9qxor0tZO3hxeBAhcmQNQQIdldwDWUyDECIhWcYH6CaBEzQMlmknQrMUGAFyCLPB8BLwhh8CT0LcjaYoU/FAr/gy0uFThlqYAgbgGSgvkPTPpuUoquCjGRScQJCyAsBCsrT7g9D+7NxTALDCd1DsQAHAeZwq6mQP2u4DGmJNxjIHp8xU2kyDMAgcBncYCjA2I/3UgcJaVc20mAJmuxi3dJ+dnVvklAmbbKgAI8iYBACT8E+b0nABGvssBIVrRCrShIESIBZT56Y1jo2PK9R9AEAwgFcJ8Bg94ISAAXJkDAKZ5TEv41YRfKL7ruS60EoKHAnliAKkFVOicTIJMDPo1nRcQoHm6DQRqwlGBwECKgMJ+FcwgtJAXQICAHcn+J4eWqnnIm1ZGs4IvG4TS30abSPtH+5MEWzspJq3lDwhKqt47QEBgvhzNbtJ4upXbICYw3C9gvoEQ/sfjIXsJHsYDdJwQTBZ9AwIFTlfEp5ddONhCU4dhItHIgsVEwScSdgAIIlfsxcBgmAfSfTHiKivah2e4U7DU9AEG4Rgs/xPye669qjP2CTAATIRv4LrWr8MLAQHZppya40/QmrSG8CPBoNiAC7/b2mbe9bjOAPisC0wZA9QwOLWNKbhGg9CRhD+BwDsXdTER/Beg+Cb4RFd1AwA130nrLjItYMAQFJgbkLgmdoHeQJSulrwrAUKyk2YO0DgB8gkEIOgoFsFMYIh1ER9zdwwGEzjdHAjHYAi/2eSnCb4uaR+WaJUBFes+VHgetnKsgtIAPInzLLYEeTjIQ6YBggiGWo/FkJHAAVTHNaqG/ff0yZmLBcKkabJlluDXESsTwEeQCYgAsjAB0U79hwA6QGBQ3wNVvCFKWcha563RatBAhc5BQkQomi1AUaVKkqGO5ChEL2S3bq9BIMBCv54LCiSyclftrhfxOjF15LnqQEyjjc4zllvLVsR4i6cmI3zvYjFk49QoEkoL+wRS+E87Dy+9hq0aTKt8AocMKA0WehgHHt0ZeLbzB8xxepmdZf/T8VQAATgjyk/Myx/tI4DA2wEibQwE1AyicExTD0Ak2ej0MRAqpvnNVh9OAjSVSjj8Sth9qjJNXY4vVyCodhkfn4/OLdeZwEeyixC48glYNqYKRpoCaudescEGyhDoNnkIqbhwwc0Bzf5jsUIbnRZWARZFtt/29NlbiwkMlOYPIKjFNoonYOEN0r6rkY3p9V2EPj3x3nAlafhwx9DwPMT5LHkH3DQOKS8gKJwrupptTq7PwxyongFiBA4Ac0w3B5gJlF0dC2oc2n0CxgDKHJjHA87jgM4HcImdS3Ulzfd2Yu1npuhEvTVzICqXtG+WR2fyZv8Xn1/AwM0zmRC1epDQ5FLdhKH4+roVxASSETzNAkzoY4iQtYkZCxXcGV4OCHR3KADrFRgjwGA3BeLaGi2BAKqRsRc6tFc0DgMEwtLox07a7SaE2JEVYaWyg0826vjEajvJBkLw13Nv1iIFVBqUngHAu051uvCbEE7AhssqjHp76sK8SdlVUumk+uKs6OoS4nekjAqYGAjKFxCmgE5rqKltU94YNAf05pBhA4NzHG4OmG/+0Ssj0x3afRxVhzLdpxQe/cifNjagMTadQa4yXxo52554WwwwGBijQFdh7EziPQwkWIR+cQyC07gcS+v3o/lkggl8JM2BynyPR9ZwDOdezyFd22//CAh2JjChY2Q/8WoSlGiwliR6qIbsqfmxHNtnlLA7ACQ7aIDgjrcY/LFpeoUOo5syJyYGdExgimu6cFohh9CaOaTQMG/u1RIu96KaIJojEs3eaOykdQ3OE+c5cY4T53EkKESXbAFBmFKmPZNBkW/gYTzgPIwJzPEx6KEd7AG0CoICGkAwMKY6EPvz+XdejyAzRduz/EyK+U2Bd+7P6vWA1U8OaEOAUD0n8ipSowRtpSYyC4bArY28N55RPVe9rc70A0xXGrOl/U3hRYAAO7wqEmSzVSFGCCTWgabtNyAglpDgHwpNHbWjfYPbpws/CU1WQgpD2HWd9jModHZCtmu8LJ/Pmrb0t7VNzTpd2Uh7TCUrH0t4lVqp3XdxfwyVDQoKiFMx9S43Y03pABwTc5z+ccGXE0MecY6B8/HAOdw/cJ6Yx5n+g95XbznqYwfs83AcBgIPp7EgoJetAHL2crb0Azi8jQ0bZWhOyGnOvNDAnk8zEgv2M12q2TaGD0DS4WbXVO/10DKvpMq++Yt8ePQ4RhsIdRwHjmPgiO8bIPgx6z2AgATf12A89cyemnvDiwABABcgoJRhD46OxQBMVArVF+FfmQA9y6wIQdnPOxOAmwEhnOVB5ud4BY+i/DEMNp2GIIXQpFIaJc+mFxSbABBZFpptLR/JghxHN1+YfscvOnDUfUWTpec/0pWNfe4DgxwMzuHC79r88dEa+3keOM9HzHlUb4GbCWs+ix34UOLjwHE+4OFwAFElJ2wAQGn3NtRaCwB0HDaCUCdmrJc4R47bV867rkBQQGWKxNvNCFoev486Iu0f+aH1Go8xTOgdAB4e4toXFT0cCJgNJCMwhRRmYYDBnKcxsPmRBYG5RIDLEgAxAS8YNUZW3YKNIhYYQFCDSOrR+cy4ZpjYPAAs/Frx6QtgwZc1LfUIcY0sKwAw40gGFIlbrincEvy45txwfLte8k6V4r+O0jDKC4E52kKQT2MC53niGCemDAcD+5hJYObBPAk43JkIt2vD7+JGUi52On28gM4H6MOMJtDZVX7CAxLMJ8yVw1crHpjTeiOmSLKBnMyVok/1HGwlQGFqdyZHTwSkqpTriNqFUf8CgIdj4OHhSDAYx4FxSJoI1Xsg1WNQDcOdgbN9znnu8vREeEEgsDIBsER6IzVpLoEuztWNAI8JU0ADKFj4q4+8XhXj2xl5WOX6SQMmcuqA6GUDAuSgIs6f8IkWFW1mkGpLzl5uncor+s0hEDtAsAkR3g/ShPQE5DMQqFtTeNP+P1LgjcqfEHnEkIHzMCYw5wPO8zSTgJnAorl4YlEMJ57jgB4P3rgtLzw4KwB+kT8X0ok5NHsqpo9OHFLmmzkOGeQDA8iJHIwgrDZIgQExgADxNFPEpwl7l7GxAKf/D2QKHGX+2NLj0sYPVMWRT0vDD3Bi6onT2cBz1hR4IwiIyL8D4LcB+GlV/cc87isB/HEAXwvgxwH8TlX9GTHv3vcA+CYAPwfgd6nqX35zMhaV71HOuyot8VfoagAxRDj/utCLn8NNgviVAl6Q5DVvIsSCIPy6BgYJNvGuaIheY2uPRci7+Psrr4vgJT2mD7MBSuGmwZ1pNMtF6bmtgJcfsxbLr8mskHpfLhwSc/vlxBwD53k6K3qEiOBRBh4eD5wPDgDzTOCYs8YPrL6fEM5j2PgBPR4KFBHgW2lKMyCVgq0voIdpxwe34QMAptiEo3hPOlLDFEgGhtL47nUX77I2AJOcixIzOXtdVNsoR6D7JdIUKCAY8QkmIHIxkMjBKKGAmMA8cerjs8yBe5YX+z8D+C1L3HcC+EFV/XoAP+jXAPBbAXy9f343gD90VyoUiWj1WexzLPYVed2zcDmOtAQPz2G6Xl78tW+/qOiRGmP4PPeRQ1pjeGvEVy8AOQaLrHQt1WS8hEAZAC5MAGvcfu50lcxFOnbprmUYtLGQTBuzLs1KIQGgcxoLsPkFzhPn44nz8RHnacdHj5unOwfnSf4AngMfAElMIMo5ZhI+POBjx8fwsTgeD3h4qMlFHzse8LGD1h84Dqqrqq+xMIEy4QgF1RhUjG+IAVGTyiHiMbm+FraYTsHhjkEpc4BMgQSCUfdGTwH4A4IAkhkDAGMDV59b4Y1MQFX/YxH52iX6mwF8g59/L4C/COA7PP6PqsHQfyoinxKRT6vq33ryHfaePRLRIMmuDvtfPDYcf3RfGgSp/SUbV7wmTMA+KizYgDSBDRrf4uhKLmKK+nefQORtFcKWdfY9JCCAGpYuXv3OX5IdaNnHqwMw8l738/DWLJBKcCTFvd8KKQA43Q8Q3aAi5qmXRwgEDw+PmKeDgncdlnOQga9KTGgAEQ7r7pMjzIAuE8wEwg8QIBa7Fj04+ziG9VQcMnCIeJpDYWiNPox8E/jVSkUxNNuGbOeQdAcNaJVZmQMEBEf0eBQQlGNQnBGYs5m7DQPha+2ImCtAPQMfhDlwI3w1CfZPAfhqP7/aguyXAHgSBAB4X32LSZFOQBDQFNEkhYTf18cUw9CQEpNJ/GEw724NjI+0MPhgeTLouIhy09xXcdq/VRZClEAwAGxCrD2loUmpDe7mAP22gchiVtRD6/X8naCcgtMAoMAgRvX7LAoRYwYPZ/oDlABgEhPgCTRhpw8ZNvjnKDNhH1NCGaTygirmfMguzIPY3UnaNlhb40/E1Ey4y3chkPLOhynQzLVgW9V3ddsxeOS5mQFHGzswJEwBA6kEgmYShE9gJhOYn0/HoKqqyFOuq+sgtBfhJ7/kYzdsGNkFptnZQfTj3vqVlRWLKKlzNbuO8J7u6Vd9BJc0MBCSHCX0z3BZKrqkqzSv9oehND4dKYUh9BVXHmzhxwD5+3plgIq2Z1Wx6ZIm+xOjJ3VImgAD7hOAa9ac3Gsa/Xx4JIdgOK8mbZ81HYg0Sja1pmiZOxOgRTy69hcYEMoRTMD2dbP3mGPSzIGTTLw+oEuF2o4/r5lEMf8BMQqRgQALEFDZuxAPcgxa16c5Bs0kGAkI6TdIf0D5PxLJAwBaz8CZJkEs63ZPeK8g8LeD5ovIpwH8tMffvQWZ0l6EX/GVX6JXICDQrBi75o93n8CdfrMLO3cJ1jWQk4JCo2kIegebsA7KlCDBj0boP0v5V+5e0vL3UXzBZfyQkaSVTz6n379ocSqT0Oiyvs/9K6vQN3bCbVcLUqgmWjJMEMopKKfgFIGcw+f0eS0FE1hMgb1noIOv9d2PtvryEIHOGGlZwk+l1j/qy5yd1hV3nuXjYV/PwIDImfUrVE9t3kaAlvjQbR+SzE5bE0zNesu2epMJDOoeDMfgPoIQblY0AFhGCVq3azlf7w3vFQT+FIBvA/DdfvyPKP73isj3wXYi/tk3+QMi7P2aPp+bZ71kJUk6/kas8uYLkSZYhuQGcDa+C8RAmJT/qMxV09M7+ZisIDSAVINBPJK1L+j9nI5wuydDWIUfrUGlTyPecRFnxVUTsfn9rPVT7FZQaayjd6UaoPiTfWLOlAmRCTmnz+urMETw+PCI8yQ2cC5MIPwCEnVlrd1MAXvvEIFqDS1OefCUpS+AWAB0Yp4HzmMQE2AgoJF8EFvHlhMfeOKOv0xrzEdQsXjvLdgcghoswD+8aMoxunPw4ahBRNmDEIOhyMeUDdxhIJnU9C7CiXM+vl0QEJF/D8A3APjFIvJZAP8aTPj/hIh8O4C/CeB3+u1/GtY9+BlYF+E/f08iTFl1JlBU2TLMRgD3ybNBkAepB+eY9/ia1WB6B/tb4xld8BdnJOLZoSlC4IOmxXXMYWdNSjQkspnfxfnCjBbnnxdL0/gZT/egfa/LszTNmKvfsInTfJVQzAkTfAhsas6JFE0FfFgbBNIBgE0BGjps5RhMwP7ZZB13j/t0aYyJecbynpaaou0xvfbBnzdxHgeOMyYhDZwJBL1XaJ+ABtLwBQBzTrfvS/jbpDP+ZFtamECOGNy7B49DLtgAg4m/k9jAJJ9AjRV4iyCgqt9646tvvLhXAfyeu99+T5B+nkRT6pjafvuZbI/YYhdLoOzSQOAwBwKAQOMC7Ee1mssuSNyI6oYCgHZ/soIdFLUhRMXm87E02KUBN7Mif7s+byuOJ4CFn++Tm2RC3DcgYoxgiFi34Xk2MDjPx+y6ssFGJ6VJG2hm2sQ4IAYwtG+Vnn3vc/iU3urWXYWdp+5avJsb8KkR0ULInIzyaD6DG8e1PKv91DNryHMHoaKmJeZRvzFHwIDzXPwBNWBo+lqD94YXMWIwteoWR1qYvjPm4MpGy2seX0qu4hvry0d83ELPc7krW72Enqs3wQdrZWuXL9IaMbMumELdKNS4AxAk6XYPukcF09Cgg9WFFbYh24llc69yf40C7CAk/2mVFXYByYab9NTocgxjDUE/zxOP56N9Hh/x7rvv4nMPnzMH2Tw8CcV6QuPXOAdnIstaC1jYGIMdj5kQp+wS7SHaRr6vWOaMLj1VHBo9GJpjSGqKeLXR1Uzx2iJB7gLO5TVjOW2Br5YK6Gn3DSgwxMptPiaoZpfgDCBwX8FHbtiw7GsMVnXEpWSDyE84wLgyF6GvcyGTn3UdNXTtKB+Ngu8NAS5/gMWqduFPAMhuMHptPCt9AGQaZAp3Tc3OOXunj9pjgacFPqJh3Bo9luYRXSudtO9pZpwCqUmDkTEzQDjRRLKBhmPw8TT/wOPjI959fBcPjw/2edeGBbfyl6oDvt4WWwmNGWWWn+t8AzRICtrq2tiB3RHdlIdPFz4cdBMAoptRykfVzImoK6ZQDbQUsbpVbNcWU+RVFHpa+oL0Q8u0OmdnUjNnD86PJhMAbjABrIUaAmPnTShuAIChvS3UUc6w6A4iNUdj+6tHIGjhNdXL4NolfQOTACAdYGvugLZuVR5XGqx82uKUNf+i/WOCToBQF3hJd0hpd2kpSFNnBYMoqxZVWrdptmkOw9RW5yPO+ehA8C4eHx/w+PiAd9+10X0mCOT8ZeoMpMbFCgDMCDYmEDmmrkRPK6e/gQ6ZDeo9FIeqLRemSl14CxNoDUWpgAOciN43ILOVn2a016lp+wuGLxM3gCkFoieZUjoLAHI58lsAuIePAAiQNm5CYI0hTIECAMkVdyzO7wtQwNLr4C9j4i95llxh+Y5CKj/tjbMJKPkESsz8x8t1qd5F+Jdq3d6lRAm9UcwyDYza72hW5R70JswBITCoMsjb2F9C6RGpvNvcmpljA6yLsEyBYAPH44HjceBBjz7smuxldW07IC3ffd4BMQFPcTkNUewgFYWWWeD3j4ALf6cOM2ts7YACgZzkk2lk9hjPK0AvplKO42YiqAKT1raQAC2FwBaPgUiaUqcDamcCJ3IY8UeNCQhkNweUmICuthaS6nUA6AxgjxPkog/24vZMZgAMPtu7k41UWhkMeHx9sgFVetp6XIGADwuiR74RAjYb7W8LfpKGiIVbI4/W0Fbg6UkrAWfA7OxoZQS8TJdO+OYgMdPwrPkED494fHwX7z4eBgLvHtA5i2bT8RDxlXwEPmMst9wqcyDkuztJKx9Vjuv4AgMLJMA1FmDI0Iq/mQE+VHosoNhZkgKUVksXz5uY1T5nCL7VjbgZID5g4pyPzal6BgDMMgNiL4J7w4sAAcgFE5CqmC4jWgKysD8WfGysQFwbh6BX4199wAkAUndcHDwR/qf5BEg486P19OTXnDEBmydXwt9jWBsuC3wQCwnHoAi5Q9nbR8OnK1+LiEiVS+Yi+q4lCqFYjfWZu1U63S+QvQPBBN7Fu4cBwLvv2lDZOR+on1xwTJtBiFjBx8cN9LyXkzSReCmnysmF8GeOos2JLTMj5ROAswA4CxEGqSENALJcdHk9t5Ol7qYvFadLOzAAGN6OjSU0JsAjMNknwGB8R3gZIICrhUZZHKXamgfVoHoXYJDfowFALJllN6yCzc6n1QhAuwZdZ916oppzcAGBwHYaoVSiJdFE3yz8kf9aVop6BrTep8QQvHMN5mlmh2vPU0e4HSSvoKI0rTplnlAMQMs5yOaAAcGB4zQmEFNnbcWfI3ci0nHgIH5f08YXFrACADcIpwjVE6BpCnB7qZZmcxiGUSUDIV9RSVzH1gpS3WTZe0xA6VJ6/+rPMB+K+Cq6CUsqRqd8zIWKui/gsX2Y8U39iDIBAbZ9B8IcANBsNvuKBCor9Zbg9/hiAv1dTTtf0Lo+h4B+F8W92Oe8Ecc8F3NASrgSFJQmTNVT28s03+nXWmCj6XtgJ6HWYBzv8pJBHWak4TPrrVbq2EokfrcCN5kqAQCYcMfgI+b5gMfzxPH4WENlx7vpaFNVW4x0DOhxuHAfDRfjnVvvwMYIqqzYHFjNF6F0pybXUgYD8E1MRt5/1ccfvQNlStZzo2xUy6Fb7WVCddj1FBshOUMzRVe3laMK8DjP7CKs7sHwC8QwYv1o9g5cMQELAQRL8wwWkOdyYQ4AMc0zTIMggKvCK21wu/nvqYp3RAOsCp4kmJtPQIj2iWsASE3caWEX/npt9Q0XC+imQJoDw4ZYZ5k59a0BEquQd0CQ5Z7sXYjUlDWAQlXBnKAuwkdfa/DA4zkwHmPNPQcnnZgaKwgpcBALcKGbPgpxJu3NgkdWeqaBkABF/VOYLz4jsxlX5KDzVYSre9TSkkN7W5l1VpK1RsDFQGDMv4TdylMCe4IMJKN6zC7CmbMG0yTAR3GNQbnQKoLaKYIn/UBTo68sIOndxgrg5S+ICY/WTFfxrr7eXRAWwWfqzjQvFtvQZXPOqdntFqMPNYWJwIC89VWPTdzq++X5PGCk9RKoYsxhW3qr27fhKFTJ4o1MbsIvnQnIfmOBsSi0WjEwNDVVDHB5PI8CgJgzH11/sThHAEAImH/mGGaz6/JBsANPTbCArJuqJ1mPWMBfzC8QecwepshiKerNFxDw3ttLNdDoJaiuwUp/zUMoodcAV7GtZE4ffGWmwMSpj22kIHcT3hteBAgIbmxIyiqZ5K1uQIBrVdAFAFx1E+Zz8yAlf9nolb6tl7eURvvS0krXDkJnAtHlFWCgcQwNsDOB9rfhDnuXo3egxg2kQ1K1AEAnVEY6TGsbdiUgrrJoDVrW5i17CgOoo/TmKBBwJvB4PmI4ExACAbbzI3Cf/Ry+kIlUNyG47FPALA25QhKKBawpj3pNEHB/gDNzuHsOIrUfZjJHbj9LHNddnKuDzm4OSLUhF/4pXoYECg0EtPcMxFiBmduQfQTNgatxAtWFromGTItvUf/0B4D9At58lV+ArEHWc7vWq5+0kOxSE4w6ALC21mQY4i0v+r9NG18wgfYuba9kbdI1f8UxOAwfMamxbyH3FjDYpYLvLCDFP1nMWg7FXErpWr2FOTDOE+cwAHh8NBNAHquXQYnKs1bOpcbmxBy+VT0LEQt/NopeWpaVW4BQfnmLqM1Lg/RFzKqb4j0NEOKY5ZKaggCgDxZSdcGPI2ybPYXV1YQBwhkzBdUGCcUxfQIfVccgsIOAxcFsounnUkcsn1hZOLU40TRuyEwtJeOxUF4+pwZDIBRaI9Jek4riMzDENfC0tdHLcSTJCADZ4uO9SbEBc7KRcITAVZ/2RZ42CJOKk6Cz6GUS6fEySPMI9GwJzWXCGIitPJUxj7SWoNuv43w0U+DxEY/Jobm89SLVZYfbpKRasozXLmzdsro6TcuBmCbC0t7K1JMcH3AApa3z7hB8hoVliTZqL8mNmhlj6cQ0LR/a3oTeflGAYEcT/Nl9ABqjBGu04EcOBALpeyQAqM0O9YYSwq/lvjVgGC607jSCU/6k2gESF0DQZnDVi1tC2jcL4g/f9noOxTgUqgeOY39C+gRkJIDcAgUL7ExiXlB0t56JpKMV6veq2taxzx2TeE3ACyCoIwNrgYT1hBjbmmJsY7KYNNamCQTRW3CexgaQ79USzgutrp73IQI9o8eBPvOx1iuI2Yo0mGoyEMSTo61ErRIzVCFXojB/uGIbJHRsMlBh5CjSNBNPnHPYJCHS9k8BQlD+Yn1a4wLSlLofAIAXAgLAxQQiBSBSWn8sVLjd643TfyPTG9V0QIjzBADSctmwkQ2eQ7KEMCdW2idiuw+F8+dYKai9Y6qWIDUGUBQ7VTPZuplbAoKwf0UKBFYAWEHA5qXHVmm0tl5QbVn7u58+AqiFN73d+egAmw3HWlGdEeTKN7Y0OTOyAP01D5Ff1uBDhq1t6LPolABAAwiW2XW85Rn402oKCXTqdZvj94R5GKcv/BErOHArqfvKb3NingNz2BTqKavg74BQIKDZC8C9AeVTWcvy6fByQGBlAgAJvlbXicCmeaGymduM+YCLZANuZwco9IoO7VZUk0S7/gYwSMXydQCAxio4CsRAJIHgFGvsOVoxtP9qCpBpEWYAC782YDCBkDEhJxYEKG2QjEFnLaUl4o44csolQAgEIwVzYNwEBXuVd23R220mrANPABFpwZECYMuRgUyLYgGdEehyfog5G3U+OhicUL82UDgRy5o300DZLOCaDouGwJiYj9J1lHBSewfjAu54aPkJEgejHDxN5zwhvm9BCvviD5iygEEwAYOAEv6mGD+CTMDketXBSQbgLTLjcs51AALR//K2u/CHryC+A8CvYt3fcGD5Ngmj9DiR6UCw/Co0/CmYUgN2mA3cAgIAWbkI6prCX2gvua4iaU0qPXUAGRPdFIjtrUQ2c2CwwF9dEwjIHJDhWmlGlfikHJEEMZMC776asR4hECuRcUPmtIMEh89PGVANwb/9mTnTjkZRukMuGEyVVweAqBNgGAhIfYeg37GqUKZ9Jh9Y21bW3fTegEjTeWJ1/kXPQGcHBBAoNjDBvoByCH7kfALwxtjjrJGHKcCCr4NuUhjVHwUC+SHhr70JKNwopx2OiDFEemHXA6PSuOXJptKO+QQIrD4Bb0V9JNwOAFDTEiZHBxuffq/3AkCgGKX9U/DH4iOojVNY+K/jwj6eLt+CYXaAXQsQqwQ3KhxrDMgJCQCA4gghIpoeLCbZEJkEh4hr9RPwffdY+KELC+DZlFmGpc3JAEBq/FzTqzYshbdR9Uxad6sDnAAaXmxqW8kdMl+aA7pknjinMycprb8DADMDFneHhFxujMpsb8Q3w8sAAdzyCcA0PYMBAN8zCgoxoLgAAOjY4+K5gFVIwrbSd4XjcQyBX80HZgdjjLzbhEa9b3s4+qP5AFYGUHHBhEnor4BA1e1U+rT7j6Kfg2bnNSZALGBIE3ae0it8zeYAYNNfs46iq9PSlqseqzdbFcxYzVN6mhMoU+hRYEAAoKo4x7D36vnGIwMAOwZLAXheCJQDAISAQGS4GeqmncxMj7WaEE3JtsvmgOXJWYAK5ilJLgQX2p/GCZRJECBxBQb+rymD+8I9C43+UgB/FLbBiAL4w6r6PfIW9yM0Wb/2CRQASAo/gBrNAXTBhyzCP+h7ZKPMBiZEPWvEToh3FAKSDSQ9LhCIce+AQGW6D0KhMjDUx8InCISw2fObKRA2aBN27k8uLaaqkLPTf+/Mqn+xOKf6WnqjM4KcshtCPq4AYJ0oM7IPPd6rUxBjOUTcQlP6HuqDk7w/fBYATLUykrHSdDpXtXk0nv9j2OSkFHidaW7Ywy1uncBV4yeQ5bKZe8nKhgu/AKN6UhAsRJPjeJOJ1QlHiualOeA+ARmuwCYgmC7oWMwC5GChNmbA22xbcFSiDRQnuDfcwwQeAfzLqvqXReTLAfywiPw5AL8Lth/hd4vId8L2I/wO9P0Ifz1sP8Jf//QrZPcJCFK7JBg0IJCiXCzs6ILP151WRsN0Gw+x8pA2JA8ToM5LiNOGnFb4Y9jzVBRDrdswVsndQSDOLS8c1wFgoINAdQ1JFoEBQDCAWA9PR4FA9mJImQDJAIY0ob9iA9yjIBIeUDM1bFBQPSOGIbvedGGO/nCP97zJtA1CDQRcr5GQshkQxxkgcMfnPBefQG4gUlo8bLCoW64PGQ4Gg0EAqdE7IAAaOUznsNUP9wyoERlAFDjdtAhBZyZAws/f5TGFvsCoAOAtMgG1fQP+lp//fRH5UdjWYt8M4Bv8tu/F+9iP0LTHBRMIEyC0fh5hJsBqCmwAMAogHDSKEpqnuOnS1ijWhAQqeOMA8miTwMRpbzRg9ZV1gsZjEf4VEMpM2FlACb5O05wzQIBs50OPZABDFXoMtz3J7h9k48cuN1IMoZbGDgDocQEILEjq8/2V5iFY9pJ6+X/vTVD1ejNaLdModyzDVt14cKENNhBr/B0QdTWqaufqW5bnubGC7g9gk0Nb7SLrM+okmEAAwOHHWkBVI32I9X8K+sK0y4cnyzEmULc5CHhP2FxAYAUHHkaMBINoA85mnxme5RMQ25j01wD4IbzP/QiFtiH7si//5PVU4tT8xACmmH8mAIGp/yL07eilJRIz+wAdhsw2JlxTC/dMp+ynbyAqWLKWvTtIC4fzvP5g1fiXQODmgDVcn16rEyPo7AghnzjPABlnAYfiUJuGewRguK9iuFZLyk9MoI0R2MyFbjKECRE2VGpE8c070mSKHBO9T3vaW7G4De3vjrX2EgBWM8gBJPrWzfnoQEBH8bRJDMrJIz8Ppb6jooEEgOoxCSfqSFbg2GW0fVhbAuCGALMAobYgVJe2iYoNrLKu5alkDqTwMxBoDZbjnjLyAyTe3rPXOIW7QUBEvgzAvw/g96vqf7t0Zz17P0Klbcj+kf/Bp/SKCQhAAGBHGQF9EtBpDfZK8JejaRbJudY6FXPA+q6d5oUQlsgzspPwh+AC4LIgFGjyz/Sf7f/NT+BAxPv0zTmgY6b9bGxGohydBQyoHtDDTBH13W+Ht4jmAwj63/a7WwYQpb/AV/mR0diADaP1d6mNHBxi2tAtnKTCcQgAMBkXr8I6Vp61tOzCBmK13xrGQ3pY6VoVwKQuwjAFyPdA1RXMLo2+AEoaYCXjgIi4AkEyFVsDQH1BUMVsFCAbfALP1Om7ZVU36mYOjB0IkgFE8w+RiSK+IrB3hLtAQEQ+BgOAP6aq/4FHv+/9CDmt1+sJRIPy74b4yD80ULDuwFFMAAMjmAHFYfa5VRNBRYPid5eK0FkxgP7JVMr6u56fK2FfuwmDDRQIuOBPPorNSWAQcBZg6+Pbklw6Rm7QEe/nDS5XJlC9A8EWRmcCY2cCqjVvIZbLjmMHgBK4NCMQNLoU8hyTiUA3OTKv8OnEuAACW5+fr6/MgdZFGHXlLKzGQ8TagWYKjHEkKxDX3HA2ianm15iKNAPymRVUFTEVcVaLchq/CL06KCxg0PxjbP6LJJjUC3FXuKd3QAD82wB+VFX/dfrqre1HqHBEXd/tmlu8lGqFoSLmVujkFJQAhfARVJx5r0fRe260YmtZAlZZ3D3GXWRrfAMCoBpApi3LsTEBIRrcnIROi03jiHfBwezb/B0qXyHI0zVxaOsxMFZzQGqQUOsNoLhtW65Ic+NEIK4UNci5DiFcwCDO8tIZWTReDYef9k/cVKWKWy080oWAdK7s/AzYkOv4BMAv8yiu/rkpI1Qi4lOzh4itFxgLWEhvD50gKHI5uQC9/JStb7jBIOrPUcrsdr6gzxvCPUzgNwL45wD85yLyVz3uX8Xb3I9QFXrulaqKXBAkpgNT+cKaw+iVpNRcGSlRVD+oXwoNbXwZL15tww4IvaGEFgHKNGAGk/dcCP3mF4BrGRodNSe9L+3rEpKAxBDkKbO25dLDv0MTfGYG63UThshLtLI0PPlT9/A0G/t0ACijscwlyeOy4g+X+bLd2BULWD+Ab22+CX2PG2Ktgn0AyPqI9gTKf9W1kvIJpmipGwBNdAsAyHZBQtqbabCeYEsEDtmdLS4QUahS9Ok2Pt4M9/QO/CdoSW7hre1HOM91EYTS/IFuQucggV+P9huGXaGnwge0AAih8em+6rMRNUFg1/q7llyFn0BhOW5s4AoQIh+paq0hsYZjJlv57kCgEv3pHfSaCbDkKRnBpv+ycrM6wtOdiVFtAM0fLvtq6gEIRMn5t0L+ifyUj0Ic0kvgL0BAbUi3ONUwB7HSp66LCTgAxJIiUm2I4N3fHrFRSj59vAawZIboMVUmyRL2jj2lcmrAIG5WJCNwALhiBHeGFzFiUBWYCxMIJA/kFTZ4NIp9BQC/N4UC2LwlCQBeWmITZaynQKBjxlM2YRXsoHAt7P4EAojmC2AA2QAB1vUZQibW/da1shcC92RI2ee1ccZIZyenoeYNXIEcKJ/U5JVeHmnbaDs75coksNT2OXgMAOrnBQC+qo+gACCWIR9i4AYgOuUsfTOfn0e5YgJ8DsgIQJDsAuTh1SHBAkHzyoXgN7bgQOC51fr6JjJqPY4EvwAg2YCWrwAC5H6bjRGgQOEZ4UWAAKDQhQkoBLTaO3L8VQo7AQFVAv/le9HlBVnyIwYNeXG713vV9sN/uJsC/rYQ8viN37+ds9Zf4uJZAFrX2PauyE+yAVAanAnEjCYNE3EBL8EOaJ6uWFbrSpt3G70YQKYp64Z/u07C7YujlE4N08LThwKqclCGORDvcQCSWgso3Y06bbTfovX5fKixJiveWl+BhZtakYMB6O07IPj65JYOQWMEJvQ1w1ClFVtjBNlzAE0GUMOSV+FffrzovqfCywCBG0wgp6DImicW+uW8jdTCxbm0MsrKcECIgk/NSwLPghLXaPegCzZI2EG/TQBYr1lFaE64sU+tu5rc0MtJpEpimHRDNSY2eXdiCPeF0Oc5Adgm/ACENAwP6EkwQPTdK7f7qoPQ+IlPDA5htpCeZRYgNdIxfAK5GjCZJWEG2EvdFHDtXw5BFBsYni/levRepSbYS240U+n3DLJxLN5mHzpvz2HVxUDJQbIBQXUdUm+KXyfusfDLAg7PCC8GBK6YAGRi4KAx0iW0pXEJBLhimoOQYDc4BT0HqME+HErYFwFJwV6ECqTRr4DjQvgjLWwOAAYAwycfTcpnaFY7lIlU6bDej+jpsNu03tnACHsasTZ3bdfx2uYTSCGkslt+F+lWOhfKRmQrgcA/3RwYuUNRe687I4SEP5iAbExgPbpgCkzwn+ohIHOglxQzh0FySQN8It/ZHHUpsegRKIdpAkB0kYaAR3MO7UhKoTGDO8OLAAHFBROIAmnepigEb7TUFdiQWavxMXVLjuBDNRNQGEXp7hASXIEACxOo0SwC3mn/qokX0Ij0qA/28f7nGMzERKHypaF3IPDxFgEGTgbK0Vn52kAs86WkpOrZ0TKzDVZnPhDsKQfrRBlyb0Ec+3O0fVcMInUxldlB5kAHH4V32te1TgOD9AmE9of7AZAgMHz8QY41CZNgg79oGSXAItT2hM2DMDPiAwKDAAdpbY4rN3OmBA4b9SdQ2L67P7wIELAuwqV3wAuUx0wn6NoN1jhY4ycAFANoVZgIuQgUQgDqNvE0CH1XmnIBhqc+8bs3CH8yAS+POQbGmBjTdw5KrZSFlmAXBNRG7Pm6h8OEIppslRnlQ6gcuVzD2wyk57yxjzhemAQFBiujWI4BMtRg4/5wCrI/IPYnvAaB6eaPCz8AG94bTMDS21iAdHCw+mUTYDQmkF6+aD+e2vAfMSuQGEDsP0s24CCkhfb2V0p266P9PJiBV4dwtWh73EcUBHDNBGKPdi31UN/739TKUVHt2/pL0E0Nks5DIOIXeR8xApQA5fkbPlf712+sgQQRAFQPHGNixnJgQukCsisuMiX0x6dTQGPnwZHktDMBzotwWVBL0iXOlZo1ShPCOIa/4JbmZ3ag7Qio1r1Cadm2+iKTAJEGhBYnMCAmEHS/egVG+gFKUQegFgik8HP7AvMAVj6RenNY6pgOBIpc/qn0EiDca8JhkV4H4wKAQn1dtf/V8c7wIkBAFRdMYGCKQoYDgQ8my9bRhFOavRZozQBQVbhocrAwhED2+xtwBCvADSYwdsG/YgG3rq081ABgmdxDKUJSwRbnwWfoxQYjCRac9mQB9AwxgdAQIqYaCMFlBsC6qwv+FRPQpPt+X7CBagmZNt7jj3sHwiQoECjBDzCoDVamzzUZXdgTGErZRBkIYpwAC7+XG/lfGhAUCnuZGhOwqBg0NEEZTcW2Ku1tgFD8dbNgF3hdrvHs8CJAAKoXTMConE07BbJBRpm64EeHFv1yefYqJCVMQg1t1cp5Z2MO/pdAwrTVMrKQxuHf6oZbr0FMIEfGRZcVerq8yCwFSsDv6U9dG57k/J6aKucRAD0681b4oQtXdRaQ8QEKIE/9DgK9HB1UAhRCOOne6CKUHClYPQQFAnDHmfsE0hdgQIAUeCn6P8wkGJ7sYgKhTAIA1s5ST71q1YXQoKEUemcC4huDFuomE8jnOQC1rkJVcgqWTmMmANw6LvfcEV4GCGAfMTjcpsu56kCtKQDJacRM2yvjxQDWkJr/gqq3RTX97ivhoDckTd2eOa4A4AoI+jkA6Bg4R2cCg0wC/tToR06nABJdg0v6WxTBo0TbiTXyqiUFm1C/iPELm0+ANLylTz2NFacI4Cq/QQLa+nFGMIDGBkYMoKpFzpEza6QDQdRFOQLFfQJIFhDrW15q/8t2xFJWbLEyEWkxIJueGYW9T0EFEkVNQeks/zkw0GuvzYCqsLvDiwABVVvsowW3m2KxpjyOaIRILcSEcq80oml01oW/VtAx4a3fbSyA4oAbgDJuCf/TpoBpF83n8eCYsIXPwR7yKD/X/C5hT7UBufWFC2aVqcel7Y8EgGABCQTMFOh58cKrtss3Ety0QVJ9w9VaphtnPLTIc/jrNdQmqJ4JWm75ZyIPCfq6l5V670ciV/ZcaQJso1ZiuRM6ptJKUNiMuWIHVJTBCjZNvx6rEO4OLwIEgN0xCDGbdqo2INAVFADXYlFwBY17g98FrybV9JV3/LH0y/Wvx98Sclxrtn7fDgiZxrZEeGzhfeCgDUdP8UU6XIBNeMogAAIgIuyNg4Uz72/C70JG17XcF703BLH5CbrIy/K+LTUENDmdOoT/tM1Mx+PRf9BQX1OAgiVFQWcZR20s9ZbJzcct6Q+grYTm1RZEMl1Cwt5AQYYxGT9Wm+oJKRbm5btSp9UU4OK4M7wMEHDU5zDFCtkXikrSN+GzvqixuP4E0AXUCh8Zn3XDtH+ZJ5/Unp6zgskKCFdAEA2tPv33bOc33wCQLKCWBS8mMMeBeZhwwEEgtCY1ldYo8u9l4+hax6pj9f7jAgSKIZAbYHvFpbDf+CZ1umpfEWjaXoPn44kxfK3yLGfNom5PjzqGia6ZSOZQKpAuQOgA4M9LxyqlMHBHqpcjI+NxlQgf7aqk+W1VIXvGgEiZNJIsRnt95JHrcKlPBoFwoN8ZXgQIKK66CEvbxxZMI8if0LoKqXSsotNrG4YyA6s9uFH4topOOuQW82IJsrCNZA6pbeg92IU+Gl20vcYIYItmlK/BAeAYmPPAcUzMeUAPBwFfw15Fcw2+WO/K2kWXzk3kdTm5Qfk7CKCDQWgsVppbmV2zgCpJSkYCm+/Xd5rwj3FCHh+pHqvsNMszkd7/V5lzPTSGcCNRJZNrGd6eGGUv1apjT2sO7qM02rkBgYTjJL7IBHiNRTnna54AgWeGFwEC0N0nYPvBlwkQWzFNsc0bhpT241rMRkAtKyqJwBq1su7YbO+YqhppY2rY4EE7AMSx2EbRQNYSqYWIojIISALTag4MjHngOKwbDBDEEuexJx0mMGPVJVWjxKtJsGq3jL4W+D1u/dgDdHs2ldVdDbQ/t/kCHAhkGAjsKyJJbk9X7M/H728AzGXuP2gsfE8r6+YNuJbvrF6LsisBTbDEnGEYKRUSfnqqFX8xPKX66mD+3gAAeCEgcIsJJAtgJhDzCLzMyjwKr2sBKtbjhe0+Rre/j8XpZglUfwcDAwpkhBsfVThro7qdLIQLIECwgkFdYwNjHDiGQg/WwKetPuQ7ARksxChDf45emwQbtYyvw9lGGr/1CIBYAPg6Hn9vY7y4L8DEWUA6Bs8Tc5w4z0fE9N4xBTrE1paMbkOvZ9GRhVxOQAF8uY9yBjpAiKRm1ZY6jiMza9czXrH1HSN+MIA6j/fPZAP2C82h8FddBgsM9DJUjr0FxtfhRYDATSbA2l9iU4YQfmcCOQtFElljExG2E7sQdhu+MYHDmEFLC9CRdilgoT8E7tUYlveGSigfBaUJ3B0mm09Ax4AetqioPdPbd2xMKrHG33lZznkgAEivcxP6HQCunYMlNmu7K+501SKXeDIrkgloZwLG3IwJ2DqDxhMHYgk1X1U6gTd5H2qsQCJ3mWGAM4beU2HJ6uWSSRWq66gIOk+MAdq6AvZT801opAuzxicEK4kyUqTo72VdbCPTxvF3hhcBAoqrwULFAmLosBIg5JyCqUkDI/NlF2KD6yvKHbvy9uWr0MuSJeeijGWPWkBIWnx3CgrFeRpjldtpcwgOF/6hh+3dR/WfrQswISUteJlg0ujxfdB+BoBLEJj9upkEeq2BSrDKa3MzkCkwFgA4nQWoAuMYsB2XYgWgUAq9zDUZ1uqrWcwDDet+rXQWvMiF55UAxQBkB3aNrxMA9vNSUVGPQu9E1UlLC6VRL+KeEe5ZaPSTAP5jAJ/w+79fVf81Efk6AN8H4BcB+GEA/5yqfk5EPgHbtuwfB/B3AfwzqvrjT77kCSYQ2y7lcszOAHh5Zkwt+r1lIP9UUbPw+ci8XFp7NQcaP1xA4E47LBuFvxsQaj+LT8AbT7AAWzX4gA41ADgU0AN6LC9JR16splN6sJMYzfvrd/X7NAkuQCAo6Sr8qamymO4vlyZy+e6ZQCABACdRHQAGAPGcmGRVINbMgdCwq/AHV8jrDq4hj2X6eDlItadmGCTVLLgLn0MDAAKKNAc0ZmxyGxavM/9LJgGWvxs7eEa4hwn8AoDfpKr/ndjS4/+JiPzfAfyvAPxBVf0+Efk/Afh22JZj3w7gZ1T1l4vItwD4AwD+mTe95AoECgDW86WhIigd/X55/uYRTlMgKLc0+9uCchkjL26CgC5RdZFaCAsTADYAYDPFhF+hx8ChBgA4uAEs2lqMCUzScrhIUgl+HG8AAEjQL5hB+A8qq95MV2Fazi8TlWXoQDAnphgQNG1JocDcFlKp90oygRT+AAAs5Q6UAzUovFbZWvpozV/n95UvBoAod2cCTilznEADgEjhbD6KdCCsZRIgROW8gUDk4Yqa3gj3LDSqAP47v/yYfxTAbwLwP/f47wXwv4WBwDf7OQB8P4D/o4iI6iYx9I7dMTjYHAC6CdDO4SsCWaqIdOdF08TxER7lN5pT8DhibcNAX0qoR/N1Zc1paQKG1HOSjlajya4rid8WO+EFMW2+ewm/IirO03eU8Ma2Y8wEWtopvUU1OxhcOQd3ZoDM5zUY9LAaApeAwO+bBviYtr17OD20/U4gclpdTlpSLSveHawphMHCum8mzAEEEERyAECW8vC3X8oYlXl2W/rN6t2GDQCk0iss/F44ybCi2dH7Sw3cAIVnEIJ7Nx85YJT/lwP4NwH8dQB/T1W90za3GgNoGzJVfRSRn4WZDH9neWZuQ/aJj3/sctgwMwA2AabPKsyNOdXplhec+VaUxtQLv7exgZqYEt74o8yBFQgaCJhGsPfcoJKeKCUnJQNAZwGdnfCCofBVg6FqbABuvaoaMKjm5qNj2pLjSXM5NIXbG/Vm+4dMb/ErC2jFdH+4dXO+w5kABMCZwh+KObT6OQXiOwwNSnsKFkDUv5sHzLwaEwj8JjPAysrMFLP1R7K7bGZR+U35LN2BwQZC6UcqfZ5DpH0tpyx/IY0PFv1o/M83C+4CAVU9AfxqEfkUgD8J4B+9+w23n5nbkP1DX/IlqstMYhXkRp+qsD0pagu8dmQQF6pEbgisFW8JYA0csju5GLvmUtToD5CgOzCI9rEc3BbRG0ykLthAfkUgFQ0vzlXVtrA7DnOgOYOZc7b8bGWeBVeMAiTorMk7/eT4NzQvQXrooz64SuIT4Fn1wkylAKgAQRIQRMRGEc7hezTu6afEpCnAFbDb36BK7nzD9XECguWljv3HkvVXMwYrLYUGdq90zVXH5e1cNoCmmWH/teJSE71lEKgE6N8Tkb8A4DcA+JSIPDgb4K3GYhuyz4rIA4CvgDkIbwcBjqMnxVaTOfpgmaB3sQIMVyxKoMoB5PFJwReKvKBJUWrStJbxoviujqqtEPJGBeWX9AwggcI2UWHAUBeYakRrn/z+LBLoRVvf+kRaS2C0tbe12ZTg2PRYQHx6N7K8IAubiAYZZYEya6bysl4+ujHPA/hi80/puyWtC6yQf6XVPWcmq5brqwCmMRluA1yHzAYIHIJpFjOoEasCyXeqJ6uuNVcIMm5B6cnP+rZWKa22GJigCxDcGe7pHfgqAO86ALwD4DfDnH1/AcDvgPUQfBv6NmTfBuD/5d//+af8Af4OPCwgICI4xoN/DqfpR1szvzcIongAad/wBhcFy+AV0Ssgtse2G6LBJ+KmAOQD0LC6ZZUamaAJe2k6FHO4IdQR17T2xX33gkA19jq/qhPXVRbh03HVBbmB36KRVhBQZSBwEJgrOCiQczdqoFTMn+Ct02t/gKL5rAwoSYnxLOAJgFkHvaxbu2BFkWwAORpTKM7u9UldIvULF05VJfein6u7HCk9WY5rvezkjvJcANCmHN8R7mECnwbwve4XGAD+hKr+gIj8CIDvE5H/PYC/AtuvEH78v4jIZwD8/wB8y5tfIRhH7/MaMkz4j7LTc5GNpRHYI8oDXEygQCGPWZKlvaoRTOgcVU2s8UDnKbBPFba2AxBaX0p7aF1r8Gd0MOAGGg1qvec9gQAf0bMhIKcW/xVf5CWHai5A4OcJlg0EQvhti3CRiJu1ApIIRA7vtj28nmlS1+UU7WIFW7FTnrO64pP5X7TvheBzPuDQaDVW+Q/tj1gvIFqRug/LwT7Ad/ozZzw90xLtbMmQFMPXJbNVd1X2+jbNAVX9awB+zUX83wDwT1zE/zyAf/ruFCCYwMd6HATHcTQWkFtEO20EhMAAaXCm0JMHuDUaQu5oIMYAbAx+RZawN+HXqqzL/GwnfrlofZHSrM2P0AT/CVDI+PvAgIWegQB89HSXKetr9nkffPTFs9BHWfbnFEgwExD3xFecQKZpRQPukcLPOwIVELBZ0O36OGf5zXraWIC28kx0QN3b2MD2gQOBVPtgZhCg0qh/F/zGCqIOqyTp7KkQQo/AJwLh+8KLGDFoAr+YA4CPlz9wHOUb6EAg9QRqFMwQvDOgy2Ne94pHsgG7bW0kIWyt4WRqi5EqsDROj0+6hnxedilqNKm9gbZPpAsl+EClbf3EsNsIzGoirZdgxtrVG5iE11Xzl288FhNwE8BBIP0BM1iBC1HuAkRgIIKVAXaTkMGgKoGzWtXMLIjBkcu4IUj7VKmxwIcD0lmA56V0iTYW0ABGujnQAGqrkz2qypryI5XSe8LLAAEBjsUcELBj8PBRfUeZBItfwH+0+QIYGNq9QDbmomIz9yPcKmQTTDThaRSauijS4QxQV2I5CK2yXTtG7wJrBdVsvKlxrrQ89rgYedcalC7N46qxeQNnIAjA5T0IsswXwRc6Ny3nIDDUxjAQKEyxrcjXTUFFhvkhLup73z59SX4mcRfyBALGfvR7mvnV/vW81koWijARAgASmBcAKDZArKC9myBnUejclrB2IigK/y7r9HZ4ESCAK8cgfFaf+CAeOZIJdH8A0f0m8GwW1KexgDy41lSFkF9A5y5wKzBkakWc1ksfeCLVSAOl00GIfgSjOGsGbiA32EBvSMECLrTKjQaSOSFfAPEpOlfE/KpWjgDZED1eHIzYHCgGYOZAgCEaA4gtwqnON38ANrMgXs+CDirLHdxB9bl++DTA1hhcoE1ukJNrAmheRp2k7U+DjxoAkDK6TEfTJr2UkwfQs54TXgQIXJsDvsR0Lv21rMCbG0e2H5WkY5d+IgoeWENU45iYXfgnN5geF41Qw0GVI0EImpOeuCOwHZHeXCEB3+15LMcS7vWey9+v4SltQd1vxQSiVJlRaStQWa5zqa8pxQYCBMQA10Y32kjHYALg+kWZAxm/OAijiCXUYwBqHLIcUKCwCN11uZWQkqiFF4DqmAWWzAHW6jEFXosFBBDkyNgU4hvVQ/VRrITAiqv3GUDwMkBArDtwjavVZaU5BKubkBtl6QP2A+RnbdUAig9Gpbs/QKQLEAm93VPfBR2VBXACdLC+DuEAjKM1muwtAFxjrUftrAC3Bf4uEIhyfvILyYY3WnnX13Uraf4wEdKXMJxhMQhMnzs/nRnEw0YJfDCDBIDVtPNyZmcMF3fUXVZ11/5N+C81aBf+TfBVUasB+XkCgBYTuBT+7hhUuHMQoNiqi9XZfzUbs7GJZ4QXAQLAbg5ArJswNp9gUNjMAdL6l34A8gc04pj1R8gfFdAEP87nFm/Ysr9ryNhYirUXb4B05DECwFPCXfetAv5cEOgaBan96/sCt1zuPG1xdB+B5CMqr/mSGBMgNhdAxWd92lHy6P0Dqf19P4lkBMEGhNJBZl8aLlGGJZOdNYEAFQ1gNybVNG0HhMYAXPD5HoHkM/jfXJ5aYNCBpjR9r7Nr8d7r+CPIBPYRgxDanx4EAuDK50ZAMrdaAxHV2LlVpKJGB+oE5pjVd89afwOBSUzA0zesAdvTZ54HAKTW96NhQDXGCJvp4d8n0t8h/JOcgmsDycbEgh8NmcjMDmx8rLrLIwl/A4Gw/bfjxFQB4qhoDCBBgK6zp4DZQAJS5AVF+9uxWAADa4tjEd1Ygnp76Ywgf5NDyQ2BGnRona9Cv/+roAGy0iJbqOqlNoL7wwsBAbnsHWC6P5Y4IBriwgKICaSOIOYgXJjQ+I/cyGICOXMshN2P6WibBQb2ajNR5rQdiTBsgklshpEAsPoApEaXgUyCTfgvBD+OyQ5usIbpYBatSAAfbCIFQI0FdIbFzCbW9WMt7D/vALABxIRt+DELBGKmY8x3mLPeKwGmXq++NZh9f20WZH13CXItH2XUgWAv22vBDxQp0WKwkASFZBRSIL8JuBYjmLD6sdWz+KmK2IFokxWsWp7SpJW654QXAQKA0Bz+iImjb/UFUFXv9rYsF6uJvrKCFhI5ffHO0AoLCOTKvrOAwAQEmDBBmWO2aa2xxl+MBNIUeDIBQqjXZcRvAIKdRprr+wYScW80+GgYYoIi0FoA0xtu+iQiPoFzAdkxqiwTAIhFgMo+KidmiU4Aw1lStNU5gZiTwFQkQaGAv319GZYvbsrD/oVeyFaIOpqAifcAKYF45FfzngYBeuOc4uwhVwK+nAuu83Ur/g3hhYBAUKw1eEEqXfaf+fcj6dZ6ozVUYgNS8aElArkBpCCoRhfbTIGfKfyTegdMww8MzAEMHVmpObiGE54ClxmAeSNHLhdfGlybQCs/g35+XW53BC0giPQGmHBXpx2Y7sYrhE/z3buQUuukU89aAzD7Yr9fo3TU9/oTmlLqnwb0gmJlGm1gaQvEJgOw9EaZKn8nzuxIGfHPIvW3P9fCz99ZonsaopkKvGcJQM5ehaTPaVeRT4cXAgJLI/CwyVAKOtWGAFCn8qFJAq2j0kGVj/68dNCBBCGEzse558q3CwvQmAM+zIwYYvsA6GABlq0yE3DiegKQ0IYENnM2IIhP5j61LiHbmwvaBDueoWoNWihdUQYSY+Jka8TWxbm+soPvJiEMAPzElq83qTMDTPPJMBDUO7Leh6TZMYa4wDAYOKsUE6bOPgRY40JVhdZPZkesBxvsE5VQQhLNtPO/+HG2ENnzhwACB74CY2/3T5TeVXgxIHAZSONdkYGgXTV90qk2ITsI/YesT0CxiXylF79r/BLIAIEOCLlRyTC7NtZAKHG5yJb/5cleCqRdrItTb9Ukt0J6yDPvN5oDtdJsPGraTaIsQ+3EABjeHKM/InKzMAAChFDRWr/lpORHL77lFThIEEXN5xLgHzAlzAhc0MfKBkhBgK45TTcLWomoLCCoFLdr/oUF6Cr8wQY6M6gyrDKPCURR32zG9ZK/L7wcELjBw5rwC2sL/6tuDmQx98ZXDiTSmMQoeoVrJmUHgYUV+PeIbitMW+pbi0lctaY0NxbtyzmezRxAZwPPCFeNoYS+vq1G5e9bmYBr/RBUZgBX4Byc/EmKnYrQWYAq1ctFovldjWkVNK50/03mAAMBa33Tsn5dRCVNF6ECCMHnMuitsNP8Dgr7v/r2dujgS+3aw8CNcrwRXg4IXCSbCzNpGFb9WmO2075KrYBFK7gtvs7Y86M1QjvOKxDIXoJyFsZL7CDu+S+k3/MXPHJhAS5slhQtvwDIL4BiKu8nKP2N0wCmdFgSYDraNum/FP4tRrY4La5bKXEwYMzUejH91uMmoMOXmkrN2V87BM0cWP1Cwv8kGNBVK1xMgsRPNgOkg4EivfvtedQ+bwl+3c9tuVKy7kny3nR/Dy8DBEIjPPH1irKtsDREvhdYmXfVrQWED4AEkbRunE9yAPLuuKtZYL1Xvh6g26lp2xEbkGj8ggSiJoeUybUbknsHPpAQSXH/SIDlNRtQ3HY9XQBAmghXAo2siw3gdB0T576LTDCzLYvrpsCq/bFr/xD+aijofoClmJIJoOrSk3PtE1g1v59n+yNAyJ6GCzYQL5Q1VRFxG5LvCS8DBHbMbN808V5vC83VWACyfNj+Y9q09QvzhwQ9tT5tCd4YAXShoBOa4wSuEhyNX/bvXAi4Z4BZzlUJlTi+hwawaL7AJU1NJlWsGwftqeiJKiHL7y+SlwBAgJm51EXoUTMubZl+0qW61HkAv+9bryo2O1Tg+xOQ9idgiAVhlZhRmAXK5hOVOblJNlHs9VWafucAmvd08b8B+glc9UZJMHh+O3ghILBoAQ9rdgoQonsk4qUVagOCoH5E+YBevCz8qmX7s9B3NlBAAAAzlr0egqm++OXQyzxVlDcKykg0rssxAvSA9txQuM/BAha2Fhe/V+TqQQEGCC0mpQGvXrkk5Mo3yY28gECpPkH1VPQp2d4UG1NB4B/imlR/oAl7Nw3ou/yH6iUgJ2ZPd/gXkPpm2+tiiUszLvPCZ/u/KgE+p0KWAH5tYBA+pvfCBV4MCFyhXgp9lkNZik2W2lLEFZLYNeTvgNNH27nA6yrwtDnmEmdtUjCGT0EO4b/lDVvOkpB4rHKaXEhuAsJFSGbQD5TfJR2tICXH2ysLP5Ossmp6XpJa88srEbKkht9bPSAmQcUGej1X7VPvyVIiqw9oNQNGsoFiifkjrVRqnkmltUhK5o0NoysmkPqf69MfwnwgABctVuv3y3MDAGLdB/ARcgm+t8J48y2eMZFDRP6KiPyAX3+diPyQiHxGRP64iHzc4z/h15/x77/2vjfo/llo/j481u12pcJEaAYA4IaAcgpJ1CGhsoZXvoS8bY09T1/mmuOX60gPKo0bGFCWVo2fvQ+RlmXfv+cEWQXxorgLEAhsSCtn0ffmmsDwZIqkxmTkaL81CU3Iq243Ey16ZrJ8ZpUtI1QzB2z4xrowLRYAyHEk8RG+qtLkfFMRVllE9wl91+6hb1bhL9MmWiPaLzI1jQ1gM2fe9LkV7gYBAL8PwI/S9R+AbUP2ywH8DGz7MYC2IQPwB/2+N4cLDEgtoUG9o5F69xwLCGsFLzXJIxUGV262I63BORcAsAr+eZ62XTYBgfkNNB15pAMySZzRtfsvN9vQcEruAPDeewbCzKgUdeZRaeuv6MJ/FbSdR4Hze1e+vD6A84kGoP3D3bTRBjrIxoxGEdD8Bh92LmYijE0wChyywWTa6Dq3uzKBb+yITrmsetnsOn43BXbI2Eo+ijfAKxhBgu4HBAIi8jUA/qcA/ohfC2wbsu/3W74XwP/Mz7/Zr+Hff6M8lQIP1xXfWUGLW4RffSGQtdBKM/RCoze3Z/N22AwIek7M+NBuua3HgBqmpnSVG6m3jtJkofUbALxFINgKP99f52vvyM4GSPG2Ul6enjRVWoO9TkTPC7MAJNPbWUEqgBAeSiQzgRSAcd1LUCZM+QVanhbzxornmiFcFjFWwedcMwPoEJFPEL1VvAQEciO/94PAvT6BfwPAvwLgy/36F+EtbkP2Ze+8A9vkaA8aGSctdn2Xn5HwZXHHqZA2bNSXzi+23rZ70aro1vtLuKKBOsAhtBxrO+Q9qYWVCKFyvkoS29so/mYIkzFSKkCNBKQbnsqdomxWpUVQxGAu7VV18xqxbGqVT0/37eTm91QumueSYM3Dt6seeV1FX7cnX3ZRgwQIXYuOXPfQPYtlQgoAWtuAjAkEMKwlWiWg2R5C8JkZNDCIPGef5EWhsVITYO1YvSfcs/nIbwPw06r6wyLyDc98/s2gtA3ZV33qU2pbTy/vzjTEtVT7xfJlw9mu2ct3gI1WlubpQheVKIjGobZLsMycKmx2J++OFNSSEh9pamqUGiUDQC+fy2MC0gpY8R09u+uskPsac15bp3EhR36paLfSBQFBT69IAEENoGFGocvrOMRvs2z4xQkGijlBE7lOzHm4WXZingPncWLMR8gpZLKdNfaDgNTknwSfLAMZtqaFDQUVYPgyackivL5HNyma1m15WsAglFGMESAgKOHn3xUgKzf7VpaCi6J9MtzDBH4jgN8uIt8E4JMA/iEA34O3uA2ZquI8H7f4ovBl7yAasviiI6gGlUiaWtwH7zh9F+DSrtxMDy9yFpwU7iE0U1ByJ+ONgrX8oQlrCnGkulR/CnOUSx5J+OEMYl04pDUZl7TAo5gVaAAqpdlzIpD9ppj72pRCopHqXlWTmmbXocdFngSs21aNJlXP8bx8V9VplpciB2iprg5aA4JzDozzEXMMnP7MOc/FXJvtHZd29BiQWWAgAGQKhjgI+Px2djY25BRXIyStSsd2pQqeN7CzAgaNDgC9O3Kttvvg4I0+AVX9LlX9GlX9WthuQn9eVf9ZILchA663IQPu3IZMATyej+1znifO87FQXGc1el+71bewATesLDSyIcPWDnufPczsY4hDtdHycNdmpbXo6UEsINZCZAAw4aC03GQEoJeifdd+n+dz8xmgfeg5obUiP2lPotuT6VxiTbZ0NYVGBoFYvpKBCpnfAC3olkMv4gACbOAJ9Lwr+UusHq1t6JyYZzlsz3ninI+Y89F7dahbl3pvonwC9JIN0M5HI1e69o8ckHH49wdqVWRa+IQKLfMsVXaZr3uEnsp4LcN2/qSEPR3ezziB78Db2obsgglEY9RR6wqOUSO4uPEU/S5BiIrORuMC0CfnsBZlbUXpWHhrTWM3LbObA5woz17WoldtyQXxuyoLLpcmBFhAYU5sINHKcDGh1GLt3DU2JOehZ3kCWLJNeUkCQSsThZlhaQ7mEfZAAuAa2rtcc3o6W7FseRzovTi2Q3F+zoHTl6Y3JrD3uFBuSpMHKMJWQcpVjMbEmALEGBBBLnzUPoUoaO1oMXOYDWwAkO0k7tb0CdQ3fa4Cn3O2rmF3D8/dlfgvAviLfv7WtiEzc6D7BARmb0ersG25yxZnSnlFXMMcmCqYKhgaw0dZK3QgKC2qmQY7IYIctNXvC1YgYRIsJko0XqGqRr2CX0flAWoa9JkEbutSZ4sJ0coyUQCeFs8HUIufBtUHCcRWrstS6QjzbAGDWD4NUstkOUVYSUrWoTOBLqBXgK5QmcUMFyA454DMgXEKTqlyi94XBn0uIHNmDt8gRW2JiKkYwxBvQjGinAW17TiBgUa7jAbAi7BQNV+ygTiXDhEMGnkMIILXQauj54cXMmLwmgmYsBkCW3YH9LDKssJekZdNgYnwJKvvdCOQZkczEFQDXTiX29Kl3X3FoACBZhIQGwDqmaq5J12ltJK9V1xQBV0+F11mCQCrhltKkyYHWZJqmC3NJU5vd5EZqUcKA4FFxoYrPb9WTjE9gn0ha+jdde5sjKXYsiwin76ZKQjMlZmAOQbnEJw2NDDfPxXLZKwsmpwanDIsABwQMIEBTRagqr7EgRYQCAwYAwwi3ZF/qvVNwFP4V2FvKqMDKDOAeM9ST88JLwIEVIHzcQEBiUk4R1JE29ZaGoJa/qnx3zIFpnVYrcLfAEBLUKUnhg5ey2KgJMN9BSO8y0HCM3eF3uia/82ofS3wVyCmBBpKLwmcVFRPgILMHEUuVZX332pEBASl6StvVmf+HTkOO+yR9HERX5WH5+WKse2mwIl5CuYYmFNwnqHdL7C0gVLYSV5nQyDTvh0A5rAfDTVmALHVk60MnapLKKQAhuui6+cXpkDT91WPGoBKTzETYLEBOO4ZYPAyQACKcy7mgETThWsItxU1/AKLtPIabQkEs0wAb7B98dAFCKjQgzLn4/ko0WS6s5C7l/IH3grXRpAicbHajn9RzOEKBC7MmXruInBRdkHfSz1Vb0Hmr//jvK8JDY3NTGM7Rxe+hgH+6b0qK1jEj2kQlYhR8wYEgnMKZA7IaQNmzhNuvknKiGYhdROvEqWQIf5O2GQw+BpGo8Q1AQDqLECJUGnOv9qLrjT8DgCkjABEj4Euvy4Bp8JU7HOe3qxlALwQEIDqzgSGADhIsIxuBy20ifxW+KtJEA0n9hYUFT+izAOimL2XgNIQR0GJBHW71bDUWI67lsOmzCX17s1b2lW9cWUmmsfGbhYgaKpueWLY5tVupAiNv2f5QSbvKpWMIMHEciQdny+abX8OMQCSw0pnlAXX1QRUsrdnEBOQKZinmQJyxjMrM0pqWtvLVhgkNTqQTCBZBAEAxIezi0Iw3TRYc6rtrMqDAEBL2GN8QKmOuIcKjeCya/1nUAAPLwIEVBWP5BMwU8tR2UFgCDCHOfhW8rgO3uwCo/DdBV0rrQK1MIKkVf7sAIDsXqtuwAKBMgXqvkgLQg3bdeRwWSotvy2K0LXCLSbAjKC/pHSdb/YRl/nmbFQlGA3CtrZUwm/MM9Lm9SHIwUjtIR1bUd/YYiwi4mMx9nsaGNK8DCUGIG4KyLA4caegsYwrNz5rfkGaNZSu+DbFNchBgAAmZubTwEAxHBSi3ElzZ25KwBMQdBd8PqavR7gcSfXzogbxmmfgwMsAAQBzLkxAjV7PUzBFHACsoJk+tTqNAovNQ3Tasx2wiw5eCP5GuoI6yyLsBQB9lCCdZ6JKKJWEolDd7rHTKwm4AIAbvRpBtSs/+brs0ou0pJiv7UZRTrrtHisTzaIJja9ZTkVjgwtH/iiNi0brAxYXDnWDBSngU7eNEUiAwSk4B4DpPqATzhYFvgQUJHeFco2/+XCkhJ9PtLIVKmWIncUmM2Y0EMCHqSe4MNeiLLop0EBAkYBarMALLiqscbWr+DeHFwECUMXjY/cJjDGdAdjOPlNj+a6+dkDPqhejGlKrDqsW6h1IZHWbuxooAurzacEmwxxhMNhno4GOPWFX3XbdrxECJHl//uTCHxAOwda7wRoD9GjARwtyppb0sFCuTlAujWxbDgBE3TUFSgto3DfAroBKFF0KEKv6rGCY/IZNN9hoSZkCmdaHH+aAnJaHYgITIuFc9gT7vIDYc6HySowoe4AkhT/yPIz4V3ECUMwET6VnXRV0QkCYOiz+WuK+mQVKT6guqHrXigl3hpcBAgDWVKfGjn8sBEl/zS4MbTLn8N1tAGDYEuBiPUXwPvxyToWgaXtXBGlH9gOQtuTuwC07uuYIpRlLCmJ/wnhbNo42LPZ6Nh1rk0hr6LXRvJTobfJ6tcpqQ+EQbd2Fzg5CYzMw5hRdZJnkzL1MpbE5TNOYQ8TjfM8GXzhURW15thzX4es3DjcZVMoZH+UvCf9VdmpmgoxRXYAyXEQVbaRpyhgBcdRQAMAm1BcuTAVyC3L+p6z7qQ7pX7aZrIuVESx1mHXJSXoeA4jwYkBgG5nHbvZs61zJ0xxCboNlny1ioLeiBn0DJhouhFxrQIJCNNgOAFHdq6TEb4MS+6w6RAXuNK0qtvJaSZFqcLnv4XLkEYKR/MKWcqI64A2nvrkV2vLOK22RWpGAoDOdEKhF6B0M9nivt2lVMhGLsUb63cQLINZRTEgVOJb0ebQN4xWas4Gs6xA0cwybw67qNnR1QJPCRgde9yJ40yhQAHIPQZXaUTiPupwrbUPehB/tA9Vs6qT7y6ra6k2zLq7r8n4q8GJAYEUwBoUVQXMuwDyN9gEp9ErnCQBDgRnTjeKhvZBCrncAiGM0oX5fVQJVIj1aFeVAQ8y6I/uwFFE2vvRnZC/Gcp5mS2cu4WQbAUq+S3KshbiFDau4BySoc5wvoHALCJajAdsswQLKPlbk8uE6JXdgsp2FgG6mWR2cfjmOATlGZyAIbR7tZSJmShoYmLgWWWdAQNUNgcEVKIQYx5LwDAR1Prfh6TPvqWdEuy5B72kpYLhRZ3Ei6433hxcDAvuiB7LFhS04fCjwnHWPhtBjAYDUbCnCDW66vu7f78RKL77RVhdXoQhH2H3RsDridxAgG7iZAXUeLbOl11XiEMCGwZrmfXOgvJODs+x0doDWPWV1dMFvgqk+eM+3aZjq4zY0QIoZEatdpZRl4oxx8ezN2rG2yjmZwEy5CZiQ/MxW7wVS/hRaMoy/K2HHAgCzg4EWG6g6BJm0oLzTX0Wz2JQTIFKRKxhEYT/TJHgZICC7wG8AwAU4bXzAGXM9AaQJoKNP7nAWAHG7FdYMpL8smgGaMADtvHOTSNd6N1en9jgWdJCtSNfI8/7B0pCa5HgSKp2SvtPYr+++phE+jhJ4ZgXSrncAuGIHCOFXW+JDBab9s+zCPLAUJguIUlNOHZwJaM7VwKiuWa6UYALmQ9Dsx6/6Z5MgNjt1p97CAgoIYlXrCwZArOCaGawMoACEmaAVA8MCFlDwC6EbBN3x+0xG8DJAALvQV1cbkGLVBGFiJgYomgkAFCiAWYE1YPEJM6n1CGXNRqy03IepHcXtoNsdCWR8ntR4/U4TEAIAogxCqOO7YgPSWKEANJuvh+t8dS2/gUGCQNxzCwBA97HAI6wmE4g4jw1lqfzW8yJ1MRzZGUAu6AGEJzLKUADonB7ti6m4+K3MIF9Jqrg0MJlxysI7SdCXc+1soDm1EWCAPK9X7YqjGA7K98cXCh+9SfKyMevb4UWAgNXfnugO7mU/WfeQ/VDCSc7aHyhQAMUHhY0VdZgRhPRI/wmncQveGEMoAUbvHnct9D6xpX2nJbPxDAaAi/hIIa8SFAKTmVpYQxTRFpdavh8LQDm+mEC+bgUGrKZAJSXJTOwoxgXYAKB6GkRsOniizUCes0Ahi8LKVNwvEsJvgDDz+VVtvbxWJhDia9q/NPslAyAAaCZEAn4BQQg1a38AbXWhZAQMBEsI4H0OG3gRIGBhZQIVl4jZEHUiOmtrCqd/oBBiBeU5dscZsQz1G0oblAZjQKhAw28bAJTwhoDqet5swb7pKJ8zgGRrfuK6pe8KAPhr7KGB3U0GMErgY709CdBYAACoOODSFPBioXNv4aMYAVVbCq8EcwuNH9pfCsdLs2oCXfyuhL9MAo3BPk3rIxPHWNuZwOL5p2sDiZkAkHVOv+Nnob+yhXz/CgCyM4M+ZPs+NvBiQGAlAn2BDniLsTXeMH3uAK8wxLQf6EIsfjvEBnro8GWouUxL22B/BKJ65LJgAwAK4UNW85y1QlzPRVsQ7W9l0ZOwf5cCJz0+BPTW8y6uZRP8a2Zwpf37dbxfGwtwHCBW4II33ZeDqNt6TgMDkXT2hd8u+9YpI6qaI/WyV8DTlCaBBoipUZXqpPeDtjgGLNb87BdocVrdiby5bLGAMgGZ8pf8ap530laRaQaQ9l/b7JvCCwKBDQXAJWMVHgIFZwKO5ReCv53HM2XYfoHwBUoQZdgF6EpQmjAmHUDWXAMA5UomTTCng0DsdqQJCB0EpCUbS+xlnP8J+rzGrfm5PE8hp9V0w/5u8f7mFWwDdPIevWYBXqnhC+jNdTpcJ9lDjc6cOT8hHG2znph61XwOAdxRSi78fp6Tfhbht3MHJ44nYE/TFCsghD9g5nmNcoz0Bguo9OZrwlFyFUL2L5gBOwYv9MiT4WWAAGkWisyzqI7I3FSF+Eiy4SXQNWJp//QdADDH4UzKKZhQGTlZKR9CKRAQ8mZiuMQ9MiF9t++zweTeAk4Vb1xb+ku0hQSLaZ5kxkJThuYnzz1KYHvuVuHvdbGBAF8P7jGoh5X256LUjQVYiYzmCzBRiHqJ8fllgqjMPB9qQJriSCYZUGU/o90gugPDGzDRnYLEPsInsKpfwvsaABTrFfauwcYKtK4ZCOofmy9LpfD1YgYAIFPAchjnt1HkOtwFAiLy4wD+PqyH5lFVf52IfCWAPw7gawH8OIDfqao/IybN3wPgmwD8HIDfpap/+Y63LO/s7CDoNgBvPLHCDFAOwDAN4rhqJ7UupQnoiFFrcb/k4YoJVFgAgRrhRveaD4MEfhILyIVQgyVoCa4DQWpBd4hl2lLSNDXv9QzHq1K+Ee8C3xlANwvS30L2fzyEQSFLbGEBEtpbjIUnKDgDmJl+G0SU/fnik3ZySt/EqTbDtIaDI+vV6qTs/+gVsGt2ClI3oQt/yv8CBK2eL4Q+GQFfJwCUYojeke4RoFddAQClw5iMcKF2R+8zwnOYwP9YVXkDke8E8IOq+t0i8p1+/R0AfiuAr/fPrwfwh/z4ZNi7CNEbPBLnEeDNSzrlb1L7W0W3uDHSOaRqLACqblcpsKSh3hpCT/eQcyquWxcmsDj/tO1wXKMedYtrk5UAYzwil+krO9evAV/bgEGgs4BiFRfMgLV+dr+NYgCNIdQPNzCIa3XmhqL22ewdzKGjMwIBdPpvvI41fAF+jG6G2E8iKH4CM9xk9Ok+xQKKFZTwA7jqolyvM9kXgq9J9JGjBVHCv4LDOnz4Uus/cR6/Efou8eB5ROB9mQPfDOAb/Px7YQuQfofH/1E1FfufisinROTTqvq3bj1IIDiOY4/fNIz2BiakNeM+R3O5aJC3RNyOjvHNM38dVNU185XGR0d+ZgK86i3tW9h30EEadQLkTLelwAooIA00QlMnAIxiBvTzdqyy7o4/sZlBHQhEIGFOrQ+K8m+IpBhzwEcFtzIXMR+voEZ/qtRipirDqL8M6Jj2nDEhMVFsCpCzS32ykZsKtohMLFQrva4VqK4laluIUYzBCCgjuaJVjGs4TdgxMXGG6NucljQWJs4Ahs2ZiPZ5YwhfgaeJddHatm/qsxvhXhBQAP8Psc71f0tt96CvJsH+KQBf7ee5DZmH2KKsgYDQNmTvfPzjeDgukpL9O7rHoQb1sMYTqZ1oc0fadkQKUeXOSo3ReY0vgXOdIqRbVgBYGMCENvs/ujhrSGlR2E79MrHt0zz0ows+b4JSwtyBJJv2FRvI3w1yBi5Hb3UFAr1hNmYGQTj+Y0GoyOJU19/+bFXb4WnowBT1OQUDY9hkMR2KMaet+zenAYGvOAw9c+GP4dtSatjK4Bl/Lnb+PcTnYqTQRxdhgUACQ5oDXdBVlmuCh2AGbEJopuOiUijohZMw/FNN0BXZQfBewr0g8E+p6k+KyD8C4M+JyH+5JFYdIO4OStuQfeWXf5k+PKxJ4WojvJS4lozr9i+v8FNCsW1RvbypGkyvnpRJdfNDS9sxCIQwb6PDlvPY/Wiucdpy6cLhch9xm8bf7fervLOT0Z4DuuLn+x8qw2YeNDAgIGV2Rs+P6wGBilP+ECSRdO4mC1DT/qoTtk6hgYLqwBhuTg2bIo5cTdinGitwiLGBIeYrSmC+AALDW2cQ8V1OHJJIZMXDwUCBKaTTCQD6uV4DAamZK3+AXpxxc6cFopAjJ1tDle3nbwp3gYCq/qQff1pE/iRsv4G/HTRfRD4N4Kf99tiGLAJvUXYjCI5xMWd0IU5q8L2AwrLdtE9nTTZwKTgsXEovDDoe7xb3IRgDQAKAVo8CqN//ltC38/3eZhfeKJ+SXGYBBHijC6nQ6scSND0exUWc18WqurDfGivwFAh0tSQAdFg52bIBTuGdficLmCY8LPQ6Rq2nOAaG+02gE5indRM7CJjvpCwFmZOIY6zV4OWPqIeID0H3e/13OaPQ2YG6DykEnY8GDurAxXHVe2CP74xzWyD0CgqC9itcEa7C/97DPRuSfimAoap/38//JwD+d6jtxr4b+zZkv1dEvg/mEPzZp/wB/g5cMQEWeiuyKFwCBWgT8A4IKwsoVm0v5td1TYxW2JrOp7RZA83vAAAeDVjmAzoD0MqVJOnzRKa0kg9grNqa830BDpRde5xgLYag708Jf51X2rg8N1MBQOwTMVAAYBrcNbEyCyAfiV8PNQAIX8ocDgAiUDkNBKaBwBQkEKhXUA5V9vKfADE39zEqPB1xnx85LuJD0GUBBPE2Kv79qv9j/QHS6GvYuAFTUWvtN5cU7L6A+5HhHibw1QD+pDekBwD/V1X9MyLylwD8CRH5dgB/E8Dv9Pv/NKx78DOwLsJ//k0vEMHmEzAAoCJMzTHpOy+AJui1OeggIcijU8PFIvBnUiVHYce5xD3GAOLnKwg8dYxGyD4AbXF+D9P3FMzQ0mhsoNP+0RkB+wdQbODSHEgBXjQ+lusEh1XghZNbLAFwam+0Xl0CeHMY6ChBUs37dMy6DifqMIefngIdJ/QUTDlT8A9vE9M/EpJuVdlA+FR4V22BQgp7nku/BjKtCMEPMIjzUFZxvrgEM59SYKBcIUtgxSSS+qn8AAwK74EZvBEE1LYb+1UX8X8XwDdexCuA3/OcRAiuege88jGrwaBG21n3nvf1NhbQzYMAglwXECRgfihypUkDLQVxS8RLxjIIvBEAcvuwrpGCnnpu85ypdUqWC+Sq9dkxuDGCAIYAEnoc4pH1TTGElQFgZwa74BewFkh4+SogGNn4oYqcjKMRF/Y/mUkxDVoVOgpIpu89YEuPnZinCUSyAFH7ADaL0EeY885G4aQ902FbgB5Cv4JCfM/CD9+LAEN3YEjeEYIfpkPyyNbO1naXV9UQoRqO6QUIWqt8Hgq8mBGDmzmg6hMwfPmH6A9O+jZhKw/Pi4a/OwLbPoHr+0MLk5A3CGg2QtwVtuSF4M8rQLDft6fr/rY47w0hAABPCPriFxgrnX+DOcDCTEIfzwhGUMAQaYkqXFlLPTSH6IYAESsKcw/MABIoyDQgUDjHhM4TSsI/T+AIIIBtHRazS2TGEmIBvuGYtR6aMwdvuaDPHQzMFPH6IQCAhhkA5GA1gY1/cAabgCARB8SMwaxnZgRxchGXTCBuiIMWqD83vAgQMHOgMwGzBWOVYYGoZCUFOk+3LQcJOi83deUcBNfXkg69ogFNHHdA2DT+AgjdH3Dx+HbuQuOsg7usg2KnUCYL4IE83SRojCFBgAS3XongA137r2xgvS5hDzNlNQdE3LwJBFekMBgAICu1AQC64DNDEJ1uBgB6OgjABhYNxOew/ETBi6Tg2UAe69M/58TjWeDNAs+OXCWmYNOX47kBBrAFbMSPZouU4KMWhq1VhK/bA7UurCGFnVhAXyTn+WzgZYDAlTmgwNTThV8gsTqNApi+LRRsrZjrXgCUdmy2cS3AkeoYQVmJnl/WkG7fPdXt11jBaqy5kCS3EL9SmhBFCJAc5oIBYLnenYRRyvQqkKBWcrD5AbAc2/fXILD2HkiqMNeSzH+yDkrgNkCIjwNHmgOnU3sCAfMFFBiIgwaNDSImoDgdCGoYd6VjBiOYVM+OZdlYBnISK6A5uVXCTIhPdm3zx/9Ss2hiT8q+WgpNel+aVALDGv+G8DJAQOTSMShTIHpCvMsnB1wD3hgMCFbazwOHGiuwt1mdAIXm8UZiGZUQ5VsiKq8V2mcD3gCFoIAphVlR7eKa0oWUsiZeTZ2LwUKyLL1VDICZgT86vklhfkL4GQSIEdR7FmYQDVeU2uaOsisLwCL8ARDnHNY7CMUU4DzJBNBgAQYAQ23fCUiAa5kDpy/nfs4T5yTAdiAIZqdhKrhvJ4Q85ZvWrgHEv6NGktqlhD9BfyuF5XqJNCHXrExuVr3B3B9eBAjgBghMOTEncAqMCcCpwFDvCLbNRdZx8qz9yzxIXYiS5iguoqUKApqqCO0/y3vbaMBbrMA3tSyhcbjODTc8LcIDWqpskIJWAti76y66C8dY7lsEHcwAmCWsQo985y0QSIFvoEAgke/ZV++vbF77ChgYAghEpml/cV8AzPd+4ihzQIcDwMxyiXINUzLMgfjMBQjSvGvHAoDgaFmW7RzFDpTyfiH8a1hNAVJDCQBK+oR/9zzxt/AiQECAzRxQ1D6ECABAILHTq5w7sH8uBwm5tHWBZsEPNkC0P+uwfpdH1/DhtJzrGgEECgYCISiWa2PImoITZREauAl9CGd2efr8gIsxAauZ0AQUxAgu4y6EneJ72hatH5o/gbcyVeKxsJ21Ia9Cv7AAVVtk9HAmcEJxqOJ0rT90QHT40UcWhlSKKxdiA1MnTj1vgsAKCOrSJ5F3EBDGxijqd6iBW5fOoPXFCESutf5VVJoCHOHvfq9s4GWAgAiOoy+LHZVe1WbIbn3HRPdR58BaOGWHKUt02ptAuH9VQaNG4v0rEBRo1M9J4NN5VJ98JVgQGJxWGj9wHLacth0PHIPixoExbCv0wbMF3SSo/RJXAERp7jyvOKsHZNrqegcGcHwAQD6X62M9oj23AYBEIc0sMKXovW1UPK0MnmUdNc/lr+j3sY4NptYWqInuhWFlFPUpQyCHHwcgh1zGQQAJZ2E4EEUMGETKkSjYRgJG2mM1xAKP5BmVzizL5bs7w4sAAQAYYwcBx2uM6EMegjHFR505EhegUvbJEZd25WzXxAtL+zMYRJSfkCuCsaSBQF7nv97wUjBjG/PhQjtGCfGoTwi+Cf/AOPzo11dThvl8oISTnYDZYEgIu7l0wQioboKV5HlcS/0un9EAqF62AlHUGzCo5NoiBF4fBQAJwlnj9M/rYi7x4GMIJzWeHH4yJOV2elOyUYg3BN+vB32XvQj5jjgPADBACAAqtFOEh4+HrhcQcDl3oWfGdW94GSDgtJZDCK7CakV9Jx2lxs49AdWiqABVfWaZPyeoZa7oUACQcTlPnTQJAUADBa1lrNpQ4Hx83Re2jQlpCbeMLvgNBIZcxMX5bvL0/QCJLbHANgZwFVeNi5UiVvMAlKfiEnUPMYR6/ir8nXEg1nWgOf6abv1Cg1WzFxDgWvi9IrP+kjkQH6D5bzIccXzQgcT0xMgWCX2AwMhrihf4mAIQAGi10zw3Ac8BQBkD5MapF04AglskEGd53g8ELwIEBLeYgAv+MPtOfFPKIT5pxOmbt7fGBLwEiQ76YJFsKYAG/fcuIGYFq8bHAgp1bvHrlOBss1tei/YXGByu6Q8SeCGhD9ufgSFMCZSwI8CAgAAlzuwLyFiphpQNqgnt2rjipEQ/BV6EvkP+NoEg398bayq1ZGzBw5H8PJYLvSn80JyzHw5FXt+vM7QSwBiLYU7ZJn6Ar14VsjtjLn8KvWl9BoBBQJCOQRovEA9L7S8CXjqvgqWBgcB5SPwwG3xv+zs7eFN4ESAAXIFAaP8YOuwTTUbNPOsN3YK0Z/RqjThmACHIGytISokFDFDaheKTgsY1M4ImYEH7pQDgOHCMA8cxcDgQhNNvDCn7P82HOgdWEEABA24IXJTTBVUvVrVr8YoHtcM0OJBXlYh6DwPLIvySL8llO2Bbp9nuMmm5awFB1jGWss/zVfC9TvM3wQqU8kKFoIqYeTi8HYxQxiHwYQIcowOAn6/CX2ZI7YycuWmNFNUVCMnzHOFSCaVPb/t7zO3wIkBAxAqSg1UkCb8YAEzlht5xL3RGew686kOjOO3XoP3OBrb4AADweQHDaiKk+dDiuF5XE6Ycfcc48HA4GCQbcK0+CDRECCAKAFMYmwbvmnfT+jdYAUKI6blo1/H8AoXGApqJEN/xsyt9BQ72YLZ8RWIJsFLX2pjdxSf8M6gBWjzQKIAga+XKoeQJEJEmlHmUEvYNBPLavo938PwBJCjNeic12VBaFa3NRCiwXUR8MdcIKd4YXgQIAMAxeqKnOgugj+0X4AtRREMLIHBNUlAQG08UgtqlpmPwkgEEEADXAt+uQ9vX8xXRUHuffwkfmwLh+Tfhf3h4KBAIO38Z+rzNiSDNfq3tF61/8z4GgriuOmk0lJ9LoemkBg4FUqvgd5+OAjMmyNj71VdW4TKusg7BL9HiODMP+DtiAkzJubAA2JgF6XKkVH6HCX4I+zgGAcNIMOAFcNhLITmm0c+ZBXgsDwCqr7TVT9ThXg/3AwDwQkBAZDcHRJUAwBhAzCUQXz1mRiPbDCpNSsWFawcW+mIDW1x84nHN4Ye6x5/dgAYdDCxDyIYWGn24H+BhHHg4HvxzeK8BUtBXwecRkVyGqFd0aviEsDfKn82HxLk4ez6EWQAPUmLB3/wD+V2cBzAUOCBmh6IEEaGRxcD2mgUwQ+sirwkEfl9SdH+mNbYqKwRr4/bUShPjiM9ogl9mgV3nxKGYBp/LjMHfUo7vHjTbXcehK/GOMt64wcX1dXgRIABc9w6MAIA5UuiHCOYwILiiv32PAPXG0/lWzE0vNrDHNUFneh/xAIFAPprOi5FwJe3mADEBZwM350FcnCNz24GwGrH6PdSwU5AZILIwG3uoa+GbG0eI/HW2EEwtwGFJNzM5qWdHHdpW847kIqh1tZ4AAjBQkxmQ5ylexQnCJ6BqA4uyPPvCLplfuRB6ui6GMPwtc/EZUU9XAIBIdYgsoeswrTa0AHPVZQHvveFlgMAFE1BVHCq+0KQtPzWmYEoAQjUq0rfxa3pOoHs9N9iA9QhQ3OS4Lvg7AASiF+2nlpLCzwkrzTdowE8AwAMeHh46CABN8Dftma8k4NtgiYV9ZQ/U6FPQ44IFnq/Z1id7f2EBzTm4CD84f7nyUaRTkbNyAuWTATAAELWPOvF64SXBt14B/y0CV+gYpKMBH12nALqQy4Xwj2NgPIxyDCp8CbNJCmViKgGAxurJ6CHIq6dXluWIrrR/4sAzwosAAblkArHApNjqs9NosQFB0eJJEl7KLyqbAeBK8wNhAqygsAp/mQVLXBPAgCMCAP6ahHhIOQUPAoKPHQ+19gEJbsgPsx4qLf/rmnNhBVnOm9YvjV+NR+o6GpnUA/YmVxygWAAonhjCDXYTZgJ82rBAmzmhxCa607XT/hwfcCH8OxCshUNZLVTMdCcwCAv9wHGICf0xNjCwdAnEl0GPdNv0l9hEJcqrgKCUikNS+kP6pGGuAXAZV83eFV4ECECwDRu2IbiuMR0A5hQTkFkAUA06YLNb5+px8V0KO5kAqsgxAjx3PH5a9HJnCF2aKEOCmu2lAQ5eSTHaj8yBB2IDq9c/stjbpgu7o1M1kKWRR0ZYs6Vcs4mwNC+y51fhRgpvfHWbBXTNXyZCB4BIh0LGhJy9UZdGrNBYml+n7Z9mAK/+TL9bTQHKWuabzjm/IoN8AhcA8OAjPQ9jgzGUPBRIzn+jI3Kqs9CSYdR2hHNeioQBuisFAu47wr3bkH0KwB8B8I95Of4vAfwY3tI2ZLtmA0pbwLcQZIqMEgypdl4MgFS3x0SrafY+yA8AAgh63Kr5dYlvGBDXJFirBiwzoByDwQSCDTSqv5xnMQnAk8dzgg1/3UlKJYmApQNBgM6iFjdTIG4vDsAvYn11OW+QBJJmx9fin6hpHHVcZmqS5t92/QUBQdQZsYALTIPSeWh8BrDIe3QJ3vNR34452tucsNWSw8k9mSV5uUVDkpgpqJsZsNToXralC+4K9zKB7wHwZ1T1d4jIxwF8CYB/FW9pGzJV4JxziZu+NZfP7lJfazAFl4mdUqZLqAkdCARQ37dA9m2P9t9KChazATRUFhIUakCQGgh0+KCgcdBcAB4eHL/pAs/JKqEtTzP6L2BTbokIXGj8fTxAvUzyR5GXK4CoV2ZtKOAL+iH8NSlU8U56X5SPSMzCPHHOE3OePtXXzyn+cT7icZ54nCfO0+JPPau96EyzINtH1G1+JEegyoiNbTs7uXVkQQ9WZ8yOtn3zvMmsupQQdNTmIQzWksPdo6z8PG/qdRwFHnsSCq7a9ZvDPUuOfwWA/xGA32Xv1M8B+JyIfDOAb/DbvhfvYxsyQDHn2WN0YnrFqp4+XdfAAI7ym1Azh89GSSCRWj9fi64V1Te1QKqHLviSAzcsrtPGPlJuNCCoXoBBQBBsgOcDxEpAAMta1cdyDcrP0gBKIxcSlJyvws6gsIIZev4YMOit2sqfnsWJ5ZOGbAECVe8GBCfFWTt4PB/x7vmIx9PAIBcH8d9vPgHpyRERY5cEALEJKrM23NiFqex+/zgA5AzCUdkOwY+1I0rRC8WLCzNc2dB5DpBaCotqXJpS6y3innAPE/g6AP8NgH9XRH4VgB8G8PvwPrch46BQTD05wqheVL5vNVVAUJUcRC9NARb6AAr7gvi8v2cRshQan0Fm80ZcWKIiFhawAkAHAm9IYsunHQ8HAYHPFWAAaEygKpLkDXx6q6pTBKNh+a+qYcpypO9XOzhuIFYTD8qGmSDcGQEtzF5AkYnsOsvKtOqbwX+Sllc1zf94PuIxWAABQTCBRv/jDZR8CSYAA+wBd0Ze7OewbfLi4wCy3o5RAJBmrE8ClgsW4GAcHSBQ+CQhLysR9yd5+/PncAH6162+M7+Z7VWFXId7QOABwK8F8C+p6g+JyPfAqH8Vrz5/GzKhvQg/9eVfhnNjAmoUj8yCMglyL5e4uwQ9GiN7Y/x53CbKzqqCSns5D7ILP8f5jak1LimkgwDZ/TlXYJs5yA2T1Maa0kiiA1VHA89/+3mh3U7LQQyBHH7xM9L+zeEXr/IW2AdT7efIuOUabMdPBwKu77NdByi86yyAgSAVBpkC5QQsfHNsdvGPbchkW6wVLPi0U7ONDhyNAWz7Xnr7oeENySqTHYiZIyH06miRE4YUzgqkKa4d/TXbaEHB/YzgHhD4LIDPquoP+fX3w0DgfW1DprQX4dd89Vfpbg44E5gk/MQCQOeaqnk9L0YQ50yQGwyEcLhkaPgAJHwBfszfC2IgS6eRff1/ZgJXzqODpwf7cGKWw6xM6Yleq1ha5SPz2EAkBX8BgMYEbgv+CgI10aqA1mbvef0t1/zZxvZnXAf7uZ7D2kT4BZgJnLG9ezKBNVS9CIxqB+hGvnNZtlF1l2s4sqA7E5ANCKIMq8yb9pei8BJNKJmAl2MAQdSPXudFW2RXcs8J92w+8lMi8hMi8itU9cdgG478iH++DW9hGzIAFz4BMxFYE8wNDPJu/w3A/gJmBMwEhATFIrzBa2hK6fQNoL5a+z4FjoS/wGA/31jA0f0BxyDbck0eA0H/Iu3BbjMqAUbBBbP7BgaNHVyxmc5soiXLmD7fIjQ8efBzea7ZV12O3ZhnnRdgOMsLMLhxPtVA4Aww0GIBzWQMKEi093KI3qZcOCQ2fx1J9xsQ8JJuIfBpGkgDgviAyrqE35/j2h8JBKT9Baj9L6P9Zit0aFsaQoIEMYbGlJ8O9/YO/EsA/pj3DPwN2NZiA29pG7IQ+BY31b3C3RTgUWDJR9MWDQDYASFsKCcGJWhS1xKazz1JofnFhV0zNlbPdY0yQvuzPTlKg4Q54D6BQc7B1R8wQjMB6JXYdX9c7Y2CrtOuRLbGa8HneNwQ/s5yVOCLvaqv60BCP2tDj9TOabNfnEcPUJh5zabPFQE9t7bT7+mrBD/qSWsEdp9AmoKF/ki+N6zrbSigMqxWGwDswg8hky1BAHQe18iFSZo5oNm0UuFoOgJZ4xtLUQ3xD7SofSojS+WM9ZxGE3kGK7h3V+K/CuDXXXz1VrYhA666CLmBrN2E1UOQjSXNBJS5kAygCifFRWGCGujMVFEkNX4KfQgKfUy2qNEQ/a/Vflcm4L0Ey7Jhg0yCYgI76W/X2nIUmSIi7A0nTR1cAwABQfoEoiFfsAJrvMWaovEFE4i1/M85Mc9Z3vsQ1LnHndzrI+XzsesCAUgsDmq+gXyXn1f34OIczPpbalZ8vQCglnkbBOB8Pdg8AIGBPagBghd2MweyjMsMaEwgvzO0ENh5lPcq2WWGxZ+0hJ8VXsSIQcVVF6Fmt5Dq2VkAU/58Rj0rG1CCAiFm8rSFVDEQYGQDL2TuAMDG3woEwixgdBAYrZtw7R3g/RHWMtqDAJjMGlRyBeb6lQ8kSg0f2S0ASO0f5ZLCH7/xa3aWaT6+xFWVQHuWrX5Gf3+dn2dp8/N0308wAV6FJ455DuMCsWT4cgwAmNQOatkyzy9KM+cUhRTqBQjGuA0CAncmUjlG9yAzAJSwBygbmzI0EHEmwNrfRzPGDtgGCNLavMkJyhxIBXi7zVyFFwEC0BsgwEyAewYSCACS8sVpSAUU8X5/dn15YG9u2vMh4KvQr+exyMeF4IsvCbZ2EXZTYHUMxvMZtNziX2pVYfbsDGoOuO8iS8bzBwIAQWVP+nfEhFL4R79OIFDYQBgBYrmsWsrbhPI8p3nv4zP52uk8fWdgVR/xZ4fwMxgkEPj7JgIIaP4AF9kFsg6RVkhl3y+Cv8a1MsONa68jr44EGkkrbbvWMANI+Nc2EH+5KRgAaCm7rh/fGF4ECChw2UWoc24+gcYCIuNM+1jzM3MIB4uEG80bQFLlbg44x2uAcJMFrEKfGqWuexehC//RVxQO34DDPlYgsCT7uSLvE1Uf5FRr0GUelwbDDXYDADIHSuDRwMDOh+3qEwOrwEzA9gBIr/1pgh7CnueP1NfvcSzs4kv9JhAILM6vQ9eb0Ps5ZvUwJARQ/kkrB1gGXTc897qMpcJyIdiFEXAzAJfhEo/aO8OaGpmbYRMgroFczMRTLWlyKnUTEvsNM4DafCm+N0ldhRcBApdMIGgd9Q/HiMFu7ynysDgM124pey7R7ay4rumGA0DV9ihWwC1AuvCPDQwqbvMJtEVFCwAkzIFFc60+jbApJ3zEmwNauS8JAHJJNqmk03kHhQAAtDJJTZmmASA+sjLNgdDK1GX3SAN7Hh8f8fh41vl54t3HAoJYckuyyAsIxJfvjqrJ922LitMaPhKOuS4RYZdHeQ5YPnLB0Ki3YyxgMBIYme4nTeO4aGtRhkoUf/lcMgFx005QzsMuIHkwWWEg0DXLT4aXAQLwHYYpBAgwENgnvqcga0TESZ5WZK+BlQEwHUb4BlYwoOvyHo/cS6AxgQCIG+PN2cPMjQtgSucsoMH72vRpZx1Ev3r1x4vbmij9kleXf32hTxFf6Vl8d2AJnlE7+Gybeyr7BM6k/Y+njffPIb+Pfu7goDAhD4AxD74Xf1BqBbJHIkQgVvAB6JzY4UVI0yjuydF+AXwLQI76tEZ1EwAKGklLUdyN0GyYW/csDZ4Zwj2/X8KLAIFouD1SU7NXBQMxeD9lXFxzxuK0iZnWoAIZk0nygh687LeE/V5e/hL4Pg+gAUIKf2nKEv6wMUvY4ZoMzgZDeM2qteXTqlSQSKDBeCg+HXE0rLr65XlshVajT+bj7ZbNAUGVQWjAOcwUmJ4ntXxN1dLyRP3TGUjddielM0HCQaNAZBZYkQvA6rrAQJRLx8FA+/k69TZ+AWBjWCKLQMVzFWZmaZX31Fl+kDTHnLH4dfmf1aaqU37NxFXv/p40lf3WB+28srECACox7yG8CBAAAF2YAACstl2rSEHNugqK732zYSdHRYadZFo/hF5ohN5o8dkfTsKeAMC+AqLITP1Lw482qMQXDkwgUFFM11wnbC+9M8tBU/DbEdEgtDtPFwcqO1WVyk1S+kvT5TkiP2zKECDoSDBQVbx7nj5o51zG8Z8p7Cen5fJDA4oQW4l7+hZAEAeEaO8qmj0fkcf1eEv48wVLi2NhsmfMQOu04fvtXh8sgzHpJ8DNBb5Gv4ZgdyAoW365dowJlh984lLmXSl+9HwCrg9bTBYG23x1f1FnWerXuYBIahIeMjxIe4fADxrkw0ygD5ipvp/GFLbRY95b0K7LngybUsm2tWUoJ86y+HtjAJpDNBrAxgJuHBNgRbiYelSAQWM2nm4X/twxSQemwm39mWzgkUyAGdN7CaCSEUxmARZ/+tDD1P5CrEDQzsOIVhfCAIRqS3ykvIIV5y0pKVptM1aHRU2rJRsERM9gRkBxGnWWQ9/VwdniGAiwMYJiAKUMGA04Iz1nSVKuQO9GeBEgoNh9AhZPheB9vVp8sDRb1gTSTsg6lio/Ed+fb0gygAKCAgBZAWA1B3h+QNOWtU/ANpw0fhsmQdBXAabEWrSxttQN4ScAMJu8+uTDIbfHmZatVlrlsp4LsIBWPw4Cg6lwr/7cZvOdFwygCz2xAKbLmNxD6AygTDlQfJRfVb32c2pbJTO8Pfiaf5IqI5Pe5IwJ2MQx8VGSy/uySfYyDqaWxxzwtgLB/gm5T9mPz5K3no0bw4rfEF4ECADYmECCH3OARrnY/02UVvncH+WNByKp9QdK2DOuAcFtNlBxg5hAd/g1J2EDAiQTYI+H9XN78sMXkjYpNZAEhH3+fQ2dPTsQEMAq/W3F7YOMIu1jHCX8CQZHgoEq3NkX/f0z5/YzGLCQXx2THWDxCah2v4AsgBBhA4Ce02uBvw75KGchCTLB97UP2d1MgKVoV+1f25zPBhDpK0gT4OI8kaDXXp2ng6KcnXeGFwIC6tpqj49jNl7pX7ONm6ZBgIHHD5o2XCv5jjoXPvceg8ECfxsM+hhzabS/j0BzAAi/APkEBEY7RWZnACT41ihixVrvF582qrKG4560uEYBg91f5Zl/WYN5udXOyGcufzZ0+GfmuSpsMJCPAgwAeMzZfJWW1mOwmAHcu6A+/nGl/ptv4ELgVvp7Nx2Wai4rg7D2pYg5/ZqDo9DtbnJWg57VHIGL/a+++OCTwh+Aj5R/T5fWuxmJ8vQLhQks367BKk7yHCJJ+fMIIPrIDSAWQV+1P39/Qf0xdjZQDkAW/hhl1h2ECCYwkKZAeUNsI86Rlb4voNIcSqFJZxf4mU45BoeYfIN2DLOCY3mT1HG44A9fDm3MBAYojAXk8N8CgPwsTkA2A6qXgHoxoKnxmfonAxBiBl7xV8292f5s66z3SRkJ9XWjADRUt/F+kjUGUzR0MG3Pmn7WdQBf1nMH/hD0FHqUn+gqWDKdHYveuu0yvAgQCO22f3F9f3TrVMWFJx/eYyARYyDg8C3+203gmSFQr0CfQDMICOp61fol/FemQLGAYALheLap+bO6uZQbyzI9VotOnlcAQLS8nIPeqIF2no5Gj69NUk8MPTDGiWMcOI+JQ4fF6QQgBgDtow0E5iybP4f0bsKvu2MQu+DzdYBAEF92DZgOWIT6sg0xq2dLu4zMbJx519o+mYrscUz1wxRo/oAGEGhsYL0OatII8xUbwMqO3xxeBAgYD7jW9sV0CNEDmTOvkv/CV2CDXVBCzUygAcA1MHRtzwuFjD6evg0tXc0DjpdeOQEEKMdgrlpEGn/S+ao9eJLO5K65BQTOYALNp1CAwLTTtL4BwDEmjjEcACbOMXAcZhIAgnkqMYFITwl1ziG4dBLqBgZh9zaTQJWAAEnRxW3fUAfZ5mNCDreZJwJbjo0TLRaHrhGr+VCokQ9b7X0+7wyhBD+PYOGvePTXtpykWfMMFgC8GBC4MAcUe0Wmps9LMADswj6u4wV0TzCL/l0KONH+lQ3IhQmw+wUIFCI3Eo3KWndqMWqGOSC2gcFsIBBdcGcTevLSn7HsVmcSbHNW47PyTyagZ8130JlMYOrEcRwIJjCn4jx1WUNAqRuwC/vZrrVdKzRt/tZL4IKfJoKbDFmzV1SfyjYLPb6TYg59NW8SdL8nfTTRJi80fvstvepS6Enzb70CviFuAUjdsyXxFkvuWb0rvAgQUOxdhLL8TUCISRZegynQ+Y/sewKBOEcCgD15BYTS+Lvwl3lQbOCNwp+TgoK8cr4LAIKa2+Fa8MO5FEJd/fF9iC4DQLCBa/8CswtTs7ldejABnTicCczjSE9+MIEU+jjXcFiuxz5acOsqVAO+cgrSmIErYIBp/AG32aPbxSVVfBBZb2W4lJJmACgQA4DUtXoKYzx+E/hFIom6b5r+Fhg0YKC2gCU+n3+JfLe/eyK8CBCAa74eI+YgCi3OGWQjkPi1xCIhIfx+PfK6+wbQjsU6qk+/tH05BzsgXNr/6xiBmHRSKiJ1/tqouh+gA0B2LakNELoU/jZ8185jrMDqbJy6g4OBwMQDCX8AwUMCgQndTOFHLSc26ZoBYHMS8tyDhQkojw1YBw0FW/ANPLzuhlbxlolAkVvrCjOg5utHS2R1qwiwrvPlUXn/BvEuvFg1/3a9av4Cnmab7C9ZQrNr7g4vBASu0q3F2yImbMPtbqvCCdcMFUWUzzVFyGE2E28QscZ7/dR/Ed13da0JNPAR/0CsXi/qE27UnxmNmvUNafwGBF7hq8avocAdHNokHV3G7ce1Wk/B7o1eQcDObfFtk7qcjCMkAn4uEBJ+eF84Cb/6rkFY3oOa1FR+CXQB88i2JZeGwjcQGBrbQ6iBQQBB1LcCqTmI3lfrKrGvSq/3Z971KRC4Fv7CkIXST1B5MyvYhf/qvL9oBTjiznf3j1q4Z/ORXwHbbizCLwPwvwHwR/GWtiGr1PegTs3inAlACqqaYJqWGFCJvmZxDIlZcK7puc7z1YkMqbBj4pCxgon0E+SqQ7P8DjrtfeqMIM7pWKSThb6DgSaNZMGpQSaK6GIKn8DiBNR1ma3458LXpt3O7W80c4HRem+png/BmSPmjG+FoGsIvDfa2Rpw6VZiub1BCzfhVdMq9diVgE1VH3hpsDwmMIfPI/N6HMEky0oAIQuu3xpAXdeFF1dcgISe40ACvG57f4sJ1CsYGXc2QK23C70s394X7llt+McA/Gp7lxyw5cP/JGzZ8beyDRkEi4Mmo7M82jorSkdV5HRXuNDTFNgJ6/sW79baXhPPEorQ8BHM9AGUOeHCr24a6EzPfwg9RFJwbFXbkc9OQV/AIBhCasgr+o5Fk2f3WwDAeq2pjTsE8Fmfj28gMMFeFlv/zytJUZtnurDvwh+rDJEWVW7RmvXLgI6sIfttjNoT18wNRUL4AxSk2MHwMp48rtgBoGb8Ld9tjYKETnsJheBvQs/XKxDyztfNBFjoP0DXkV3tSWpmMJedH982E1jCNwL466r6N+WtbkOGayZAf3J9No53pDcAGBgynTLWHHjBhC2CU/6AeoG2l/UylhJ8ZwJtDIGDRPoZ1G3/ABDXmjLEp5/WpqGr0N8EgQYIF9/x0Ny1C275dyXwVzHBBGz67jKDznDUQXlYQyZ7NkEAaA07mc4TdV414wCR0o9kAkIOuxR+zakYPtyqmMA6xLjG/bjXIN6xNL5qY9ean9tl+7sAwyXl90Li6yQ4EVevBpbzfCGxJ2YDVY73A8FzQeBbAPx7fv7WtiEDkKP//OriBst5Q2MEMDj196G34TgSb6w2HHdgK0ldqphAoXUbpiAHI5gdJBwAovsy46SAIN6pXsOsHdkMyMZDAh/fKX0HpSG36+zB+C5XKrgS+JUXxEiNoP8zhV8CBBSIOU4SaVk/xBCi7Ra8UANvErMLIbeE3JSDBM/MAav/CXHqb+dC3/WBQygAQHcbskmw6AYCgysmcAMUWNBXzb+YA9B6ZwcEToSDryc4sKsUluUier2eE+4GAbE9B347gO9av1N9f9uQfemXfmJJt13kA7UVL8XHFwMD06mjmwNpFphWCeegLiXeK7Uapq1uM5qwi7hJQYOLsteAAcABKL+bDAK7sDdQoDQlPVzOI63hO6hFREj487yL+QoA6xVye86oh1xEMD/GBMTG0iu8gQOqUo2awMDbSBOUtbZjFGjFaP0WcFbA6pGpP2l/kNPQhYaFHVomR6PV7fkrCjAwEGjn96RKtM5L4FdW0K9BRXN5hJVtpmeR8TID7Oq5QPAcJvBbAfxlVf3bfv3WtiH7xb/4y/TKJ5CCEvnnCmFFAtP0Ep76YAFSgDB1QggEGsJHRabGCXYxOyNIQOBFR0LwUUIPGAPwuGydUfmRho0RVBo8RXXULSbvr14ERToSsWv/nfz3WMCeId5BX2yAy90atmA4IPia+A4AfA7XtplPEmwAvewiouU8rigN8VS3EdIJGLYAAhCs12CVmepwYuKseV8dCxS6GUdCS20ny4fB64oFrExg6pY/R70FMxXl1Ix013Uqnzh/RngOCHwryhQAbLuxb8Pb2IZMkBWYwQta3Y4jnV0fR1GBFAuQSccyBwRuDmRFdqFXigfgQsyCH4W8goNngAT+Ki7e04VdW+No93BBgNpCiwsQ6IDS4vSKCVwzAkU4BZHS0JSvAt5jmoJoo9xsJ52oMI3vEqxXke65CQfkemcJGx+drzSaQJofzA5q9eWSlgsdeSU0pI1b/oGlruK+EuZsqxf+gFusoB5U40YrHUI3dGrTyAxQY1yeEe4CARH5UgC/GcC/QNHfjbe0DRmAy96BYAEaDqF0DIV2gVNTFAvAFRBI1nPTwjeFUUvo2RwYsoFD1gIbl7I0OOGGwsLpWkVnAp32FrG3WLoOzXrNKEJg6l23zIH8J7XdqiVspnosrRRMQEj444M8L4HoILsKOWerRm4gFV/mM+rNY2bUqwKDBMa+c9EPUOByW4edr+VLwFP2jJdtYwJ1LDxavrsS+G2UIIFAcpF4Hgk/TXDoMs7mKrGbZwDBvduQ/fcAftES93fxFrchWyujswCbZFMNGzSuPophF/oEAkQXITXI/MyqYGqsWags+CqolYFDey0AsOaFTLkVbHS5zsa2PEv6SX8us5lskAGQJXYm+jeEP4HBH+vCrxhoszunQocNJpI2H9rKqIAgM9zAqMnqRdUHECSyR07id0LlQyjjnRbEBEhjAjSQSIAYjiwBOvxuP2/lVvnZHbkM7pEc/54ZQBN43Z2EuApsnMTDO4BdivkCBveElzNi8IoJOAuY3i5q0IsDQQhsDNhBF/oYIBS9BQCDwD5Dr86dxa+mgPcSNCYAbwjJocHtj65Jm9wAgbguDRV+BTp3MGCCCFRDag5E/n5jAysARFm67lR2DoYgD2u0MtIcsI8PiFo+otHZGHJE6NCebmXN/pBqBKEM+NekrrXfC5RPQFSy+9DqKFYM4pq7oAJxSGHW1EYp9I0NrGBM91zMILzNBICqfM1jivSFjETz8Ca6MYJ7wssAgQtYC8GKhTe4ueZ21ghaGAN43BygwUJsHgAobbgMyc1FH6LCmylQgJDxBAKWXqJxBAgskk3ra6RjBwKA2EYDg+V6LS+scV2jlsPwNhyIl1Ku4Q738iO6Z0cNz9aBWNkZNDLSRa+0Y1JppBbdGwAbA2SDEBsMIFHQEvJKgrDGqcIWakEt2yYGEJqKYQcCvTwLNlNCjKxTv+MuJgDapt3i+8vFHbOVNoWbp0lVlqKLdpptdb3p6fAyQABPMAE/zgAA/iSNJnMAMNoOVO9ALN0FlPDDhV9rKG50tam6OTBw6SDkKce9mfBxidF69yr8OaYfBEBN8IONoL2/G7cUhE6igb5R/BkE4CAl0ByEFVo95heYdOawaIWDgJteOnJkZ0Fb0+WZRgkAkOYVsPsCCOAC5aBAhWx/ZI2D44j1HKkPDLKuS91tZomXxaMYeepc6boJfKSPAWEzAyx+LvEIjSc1jyVslvRlKQr4E7fKpRpImMz1GeHlgMCiHRQ1ASUaUZU//+Nf9JagPF4AwQRcDOjZ+Q4tqznoZFDvuA4/gEBsP76UM27qi/Dn80nb3zIL2nuFq/nyugeJttSikokgGh3rVC7JLqohkF0QrQxD44YAJBx6o2ZRbnmk1ETasgFrZsFbvGKI+NBvAySN8SC0+69sn2JA8WxFTeKqdhKMQKvZZF0tcKXLh+J0+T7b6Y3P9ixKklbWe3O+NAUUbUWU58l+hhcBAqo2+6zFkWBMxaK9CjyT3nHJbZWeT8x/U6pR5vxxpvGJrNGYUz94WbveZOSnJh6gkHCQwo9N8Pl7VU0ASDFaFF2lpp9EY7ZLalWZ+67c2gN74VMZAmSVZnn3UigaX959rZdtklMvqmEUSmUekWaSHAKoDExHCdujT31jKCWWpAUKuZ2kVBwDA5CMYKP2JKlrOWVxc1wId2ZLQCiCpLRcLlQs8bzQ6Kn134NgmxIBZfbN4UWAAHCxF6ELSznvSHgYo4WaIY06E0lxjCde/CPh8FVoDAxW+zTeVs9XoNPd1K64PtdKdWMDyz3xvCb4Sf1CwDwyVrn1fGdD9B+2dnBLDa0NPvPOCob/thKwctaVxgd07OWTH6YrIbyRLQd3FYHKQExrjkFMsVFnLDQQ5ybwBQTxXfh0sigXyOp50l5MT4W0TQJw4zoz1hGDhD8xUunt7tfKguDnVJHXMwKQFzbAbfOe8CJAQKEbCEB9QgqoN2AVXukNP7VJE9w4m466y+9J+BC/dyAAgUo8TeBIDSRzSBag/XlNu6eQEogRWLA5AWoIXfArr3GfcLvz+NyeLRGEWMCqtdqzu5hzQ2ysgMtIKzEMGvzIymeHZZa0fFNRA8tb7t0Yu/pqDVbipYaCCQnq90Dzp+SH86Qkm8zMVhRowEDKBmt5BgugiuFHKcFjtAeVXfN3FL5JCPgn9Uw8CwVeBAgAZv+3oDU/Pe2pEh9aOIJ+EoD4RAFcsgHpDbTpM4kYQvuiAIvwk9ZrdrDWvQ0AljhuWJVgSoeDQktgPw8HWzTWWHRzZQHFqrqyyixiEfwsBY9NIqIlCOnJVVC2stSxfELjs3CmMzS2afMt0uFbk+cxQMCPWefJKAwhr+Vf97MAqzQJIk+FElnc6kCrxCPYBFjP40XxqNUkiGMoMD7P9HVtT1msB+dvgh3fF14GCCh8bfwlWmvRCquPlcLDtbJuZaRwTYJWbihmsQABf1YwIUaQz6eTFPbF0de/A9aa32HHY4SEfbHtWbAltEqaBdRIo+1pPbk0Hb+2lSiVPjehKsEAgvrLZa5bHVSudDtubyI6H4KfS7MNtXPawxEyq9Zi9SNR+PbUvSASCbg1VAH1GlnLgtMqdF/cGlqfGUKMmqy6a/4Fpa8UaQpklfdi76E36H5ODUEvfnoVXgQIKC7MAYAYQBxL+DOHsmQ2C20vgmqCesGhqHFqAbg9suvoctxogRN9Svh5WS1O05I26fEhpyXUrNGXTAUDEKR9mefMiPhUOa/XTSV0SYHpupo/CTwpou1pSmXOwpOJCiGOxu8sgD52LbbmozOBfFKe+1RofwZhJrK7dcshpxFQamyNBayYcAl13Qy4EnjOcuEvgXwiNwEXlXn1TS0QTVhX17cQZA8vAgSAK3OAQMBLjOtj0yXJokqb5oMaI3PqqDFQtuulGJwUz+UxGu2MWhA7MEFgECvoZqO4AB9ZJUeIciNGuPlXV+dPAIBoPhDJThjoWr4Kphpt1h0IuPnv4rAs/IICHW3vCiFuP6auPxdcZwMBBGKrnVu5QvwYdTgrBQ3Esxiq8EJoiT1toxKpdOwkBJ2zwUzN6yBaYesVwI1zL9VNsUmSmcoEnXBbAIqIxOFSY1yHFwECiotdiUP4GxBIL3v0qjIKfyFVJNarEZD/vL64MPl3N9O+sIB1Ge+Iq0yhNcis44XeWcWSNr9QPGtcOgklQIIaaHNOxgO9HKhBcmMz4dfWKHcg0CVZtaZAJLMqs95rX2qRFbbh3ScgpP3lEAODBIEAABN+m+dg55LtRCkN/JfS3WjlKuBPtQD6HQPBCg5Ae3wW93ruP2mWfLbFVaPf0PBUtzU0+s3hRYAAVC99AqGFuI2Cr1OarLRYlxUjWB65gkAKv79JQIJSv0oAXr5bhb9YgA9FhtrmkxFSQOucBbpp0ab1LWG9N0B8ssvyjHi+VhtisGRnZZRJmDb1GP5b5b4KvlC5V7OXutaEGir3yBSVrRrg1NBX2ZdvP+wTTEDz+XFtsxqbs66KfQut1aSy6YyzNcAtbPBXT9wYA/I9l+eRRn7XG/r6C0A5R5Wum8lewosAAcWFOQCkWmvCn23XWntfjYT01cYIgBT6EIL1HH69FSolZ42DAcC2XRjvRU+TkjzljF1o0m90BjWENLPae0RaY6nvbRUlu8gNODzdPDcBoeUWx1g8cIMA19RXDtgo92z88V2+txUgNU/NG6tXYBH8MTCOAoCRIBD1ZTMcEmwcBGawqL0JVD7p69b8FsHNpDLa5j1lIug6SMgTqvxcfr4DVfO3SMP/LMub2p+fS+z4IzdOAAB0HSwEtFbfMYIG8lxMtrjxBqqDsk/DFEATfqRmXH+b14nm9oy2pj9v9hFggEpqzDsIrZ7CRiCRSjJGtF2BRAIDNfjUqmjAk70CIfxN7Cl3KSQl/JrN0Mu4vY7KXSn9SzXoUooBvMxuAhxFbJjwkAKD2N1pHIMAuxYTMf/LwPQvhlwAgQJ9x17tmKCLDMPLdqmT7plu3xIoEGXT5RPlo9SOFaT5SZrpcg0dLBTVgKni7wgvBAT0BhPg00X/dI/dheh3XcUA0VgAA4AWUyjAX4UHBRCKYgG0rl9o/84GNIW/pTCYAMhGFSWNjpToAAS2/bvA1+SYdUhs5tuFVT0fVXhrCbJ+6uJeQFCGwTqSIOmxrsB8DdJ97L+kORAAMBwAxrDNBRRwgff60uH15sKf8zxQANUwQVsZlN8JluY3JpkEbhHwyDvTfcJIXBYHEYxsIdE2dI27HfTNt2xhXdTrhYU31ITQ59Y9y++1Xd1+Wz4/v9PtPuXYpkG0vW0VxFUrlnp4OmX3W3k3wqrl+N2XV0+X6PV9XDprSazK7bpOExdZm+VsITarpKKpHSz6dIHdp9L+/G9Z8G++aXnEJRhslxeiLLcu31+7eOEgcH94Lvp9MGGXsrur533K9/PC23jZM59x4/Y31dsb6/U9ZeXzVdgLKvmr33Nbfa9t6w3hCwYEyKT+cBPxRHiy0uTziQP3l9R7L9ObautZ4S4tfXfB7dzgfYcbj3qK6dxK7l2p+gAayRcMCGwOnRcY3rfWe2vhzpJa/V8fxDve8Pqny+RC0z4ZnjIG32N4ive/8f67v6rwAVCjLxgQeBmhW7wvNzwjfTdv/eDz+PZB/QXUyxOM9bmpe1u5+YIBgWf0iHyAgTzGS8yt6/cS3r9w3PmE9/Wit1MhbzQHnvWaD4ArvsV292ExWdGrrrnPdyJE/j6AH/uw0/EBhV8M4O982In4AMJrvj564X+oql+1Rr6QcQL4MVX9dR92Ij6IICL/2Rdi3l7z9YUTvmDMgdfwGl7DewuvIPAaXsMXeXgpIPCHP+wEfIDhCzVvr/n6AgkvwjH4Gl7Da/jwwkthAq/hNbyGDym8gsBreA1f5OFDBwER+S0i8mMi8hkR+c4POz3PCSLyS0XkL4jIj4jIfyEiv8/jv1JE/pyI/Nd+/Ic9XkTk/+B5/Wsi8ms/3Bw8HUTkEJG/IiI/4NdfJyI/5On/4yLycY//hF9/xr//2g814W8IIvIpEfl+EfkvReRHReQ3fKHU2XsJHyoIiMgB4N8E8FsB/EoA3yoiv/LDTNMzwyOAf1lVfyWAfxLA7/H0fyeAH1TVrwfwg34NWD6/3j+/G8Af+vwn+Vnh9wH4Ubr+AwD+oKr+cgA/A+DbPf7bAfyMx/9Bv+8lh+8B8GdU9R8F8KtgefxCqbPnh32hzM/fB8BvAPBn6fq7AHzXh5mm95mf/wjAb4aNfvy0x30aNhgKAP4tAN9K9+d9L+0D4GtgwvCbAPwAbIDs3wHwsNYdgD8L4Df4+YPfJx92Hm7k6ysA/H/W9H0h1Nl7/XzY5sAvAfATdP1Zj/vIBafAvwbADwH4alX9W/7VTwH4aj//KOX33wDwrwCIdd9+EYC/p6qPfs1pz3z59z/r97/E8HUA/hsA/66bOn9ERL4UXxh19p7Chw0CXxBBRL4MwL8P4Per6n/L36mpj49UP6yI/DYAP62qP/xhp+UDCA8Afi2AP6SqvwbAf4+i/gA+mnX2fsKHDQI/CeCX0vXXeNxHJojIx2AA8MdU9T/w6L8tIp/27z8N4Kc9/qOS398I4LeLyI8D+D6YSfA9AD4lIjHfhNOe+fLvvwLA3/18JvgZ4bMAPquqP+TX3w8DhY96nb3n8GGDwF8C8PXudf44gG8B8Kc+5DTdHcT2u/63Afyoqv7r9NWfAvBtfv5tMF9BxP8v3OP8TwL4WaKgLyao6nep6teo6tfC6uTPq+o/C+AvAPgdftuar8jv7/D7X6QmVdWfAvATIvIrPOobAfwIPuJ19r7Ch+2UAPBNAP4rAH8dwP/6w07PM9P+T8Fo418D8Ff9800we/gHAfzXAP6fAL7S7xdYb8hfB/CfA/h1H3Ye7sjjNwD4AT//ZQD+3wA+A+D/BuATHv9Jv/6Mf//LPux0vyFPvxrAf+b19h8C+Ie/kOrsuZ/XYcOv4TV8kYcP2xx4Da/hNXzI4RUEXsNr+CIPryDwGl7DF3l4BYHX8Bq+yMMrCLyG1/BFHl5B4DW8hi/y8AoCr+E1fJGH/z+cv4KpqfjIGgAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import mindspore.dataset.transforms.c_transforms as c_transforms\n",
    "import mindspore.dataset.vision.c_transforms as C\n",
    "import matplotlib.pyplot as plt\n",
    "cifar10_path = \"./datasets/cifar10/train\"\n",
    "\n",
    "# create Cifar10Dataset for reading data\n",
    "cifar10_dataset = ds.Cifar10Dataset(cifar10_path,num_parallel_workers=4)\n",
    "transforms = C.RandomResizedCrop((800,800))\n",
    "# apply the transform to the dataset through dataset.map()\n",
    "cifar10_dataset = cifar10_dataset.map(operations=transforms,input_columns=\"image\",num_parallel_workers=4)\n",
    "\n",
    "data = next(cifar10_dataset.create_dict_iterator())\n",
    "plt.imshow(data[\"image\"].asnumpy())\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2. 使用自定义Python函数进行数据增强，数据增强时采用多进程优化方案，开启了4个进程并发完成任务。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "before map:\n",
      "[0 1 2 3 4]\n",
      "[1 2 3 4 5]\n",
      "[2 3 4 5 6]\n",
      "[3 4 5 6 7]\n",
      "[4 5 6 7 8]\n",
      "after map:\n",
      "[ 0  1  4  9 16]\n",
      "[ 1  4  9 16 25]\n",
      "[ 4  9 16 25 36]\n",
      "[ 9 16 25 36 49]\n",
      "[16 25 36 49 64]\n"
     ]
    }
   ],
   "source": [
    "def generator_func():\n",
    "    for i in range(5):\n",
    "        yield (np.array([i,i+1,i+2,i+3,i+4]),)\n",
    "\n",
    "ds3 = ds.GeneratorDataset(source=generator_func,column_names=[\"data\"])\n",
    "print(\"before map:\")\n",
    "for data in ds3.create_dict_iterator():\n",
    "    print(data[\"data\"])\n",
    "\n",
    "func = lambda x:x**2\n",
    "ds4 = ds3.map(operations=func,input_columns=\"data\",python_multiprocessing=True,num_parallel_workers=4)\n",
    "print(\"after map:\")\n",
    "for data in ds4.create_dict_iterator():\n",
    "    print(data[\"data\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 性能优化方案总结"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 多线程优化方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在数据pipeline过程中，相关算子一般都有线程数设置参数，来提升处理并发度，提升性能，例如：\n",
    "- 在数据加载的过程中，内置数据加载类有`num_parallel_workers`参数用来设置线程数。\n",
    "- 在数据增强的过程中，`map`函数有`num_parallel_workers`参数用来设置线程数。\n",
    "- 在Batch的过程中，`batch`函数有`num_parallel_workers`参数用来设置线程数。\n",
    "\n",
    "具体内容请参考[内置加载算子](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.html)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 多进程优化方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数据处理中Python实现的算子均支持多进程的模式，例如：\n",
    "- `GeneratorDataset`这个类默认是多进程模式，它的`num_parallel_workers`参数表示的是开启的进程数，默认为1，具体内容请参考[GeneratorDataset](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/dataset/mindspore.dataset.GeneratorDataset.html)。\n",
    "- 如果使用Python自定义函数或者`py_transforms`模块进行数据增强的时候，当`map`函数的参数`python_multiprocessing`设置为True时，此时参数`num_parallel_workers`表示的是进程数，参数`python_multiprocessing`默认为False，此时参数`num_parallel_workers`表示的是线程数，具体的内容请参考[内置加载算子](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.html)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Compose优化方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Map算子可以接收Tensor算子列表，并将按照顺序应用所有的这些算子，与为每个Tensor算子使用的Map算子相比，此类“胖Map算子”可以获得更好的性能，如图所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![title](https://gitee.com/mindspore/docs/raw/master/tutorials/notebook/optimize_the_performance_of_data_preparation/images/compose.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 算子融合优化方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "提供某些融合算子，这些算子将两个或多个算子的功能聚合到一个算子中。具体内容请参考[数据增强算子](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.vision.html)，与它们各自组件的流水线相比，这种融合算子提供了更好的性能。如图所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![title](https://gitee.com/mindspore/docs/raw/master/tutorials/notebook/optimize_the_performance_of_data_preparation/images/operator_fusion.png)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "MindSpore-1.0.1",
   "language": "python",
   "name": "mindspore-1.0.1"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
